这个问题在这里已有答案:
我有一个Answer类和一个User类。
答案有getUser()
,用户有getPoints()
从答案列表中我想得到一个按点排序的用户哈希集。我试过以下:
Set<User> collectSet = list.stream().map(Answer::getUser)
.sorted(Comparator.comparing(User::getPoints))
.collect(Collectors.toCollection(HashSet::new));
collectSet.forEach(a -> System.out.println(a.toString()));
不幸的是,这似乎没有保留顺序。输出总是不同的。
有趣的是,列表的相同示例可以正常工作
List<User> collectList = list.stream().map(Answer::getUser)
.sorted(Comparator.comparing(User::getPoints))
.collect(Collectors.toList());
collectList.forEach(a -> System.out.println(a.toString()));
我究竟做错了什么?
HashSet不保留插入顺序,但List确实如此。您可以尝试使用LinkedHashSet。
编辑:另一种选择是使用TreeSet。它是一个集合,因此删除了重复的值。并且元素在插入时进行排序。使用compareTo
方法(由Comparable接口提供)进行排序。例如 :
// Answer class
public class Answer {
private final User user;
public Answer(final User user) {
this.user = user;
}
public User getUser() {
return user;
}
}
// User class
public class User implements Comparable<User> {
private final int points;
public User(final int points) {
this.points = points;
}
public int getPoints() {
return points;
}
@Override
public int compareTo(User other) {
// Sort user by their points (ascending order)
return points - other.points;
}
@Override
public String toString() {
return "User{" + "points=" + points + '}';
}
}
然后在你的主要代码中:
// Main
List<Answer> answers = Arrays.asList(
new Answer(new User(0)),
new Answer(new User(20)),
new Answer(new User(1)),
new Answer(new User(20)),
new Answer(new User(10))
);
answers
.stream()
.map(Answer::getUser)
.collect(Collectors.toCollection(TreeSet::new))
.forEach(System.out::println);
输出:
User{points=0}
User{points=1}
User{points=10}
User{points=20}
Collectors.toCollection(LinkedHashSet::new)
首先,你根据一些Comparator
对这些条目进行排序 - 给它们“一些”顺序,但是然后你将它们放入HashSet
(顺序被打破),因此结果不同。使用LinkedHashSet
收集它们以保留排序顺序。
如果您仍想将它们收集到List
,您可以:
yourList.stream()
.sorted(....)
.distinct()
.collect(Collectors.toList())
操作本身的顺序(distinct
vs sorted
)matters
也许你想用TreeSet
。
两个用户相同没有。点不相等,所以应该有一些uniqueId
用户。
我认为它是userId
这里不需要hashCode
,equals
(但很高兴见到documentation),因为TreeSet
使用Comparator
(或者User
类可以实现Comparable
)来确定两个元素是否相等。
TreeSet<User> users = answers.stream()
.map(Answer::getUser)
.collect(Collectors.toCollection(() -> new TreeSet<User>(
Comparator.comparingInt(User::getPoints).thenComparing(User::getUserId))));