用于设置和保留订单的Java Stream Map List [重复]

问题描述 投票:1回答:3

这个问题在这里已有答案:

我有一个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()));

我究竟做错了什么?

java java-stream
3个回答
3
投票

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}

5
投票
 Collectors.toCollection(LinkedHashSet::new)

首先,你根据一些Comparator对这些条目进行排序 - 给它们“一些”顺序,但是然后你将它们放入HashSet(顺序被打破),因此结果不同。使用LinkedHashSet收集它们以保留排序顺序。

如果您仍想将它们收集到List,您可以:

 yourList.stream()
         .sorted(....)
         .distinct() 
         .collect(Collectors.toList())

操作本身的顺序(distinct vs sortedmatters


1
投票

也许你想用TreeSet

两个用户相同没有。点不相等,所以应该有一些uniqueId用户。

我认为它是userId

这里不需要hashCodeequals(但很高兴见到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))));
© www.soinside.com 2019 - 2024. All rights reserved.