在Java中查找具有流的重复条目

在Java中查找具有流的重复条目,java,java-stream,Java,Java Stream,我遇到了以下问题: 我必须和学生们反复浏览一个列表,比较他们的ID以找到重复的ID。找到这些副本后,我必须将它们写入字符串中。到目前为止听起来很简单 students.stream() .filter(i-> Collections.frequency(students, i) >1) .forEach(System.out::println); 但是当我尝试上面的代码时,我没有打印出任何副本。我知道它不起作用,因为我没有比较学生ID,但我不知道如何比较它们 我的输

我遇到了以下问题:

我必须和学生们反复浏览一个列表,比较他们的ID以找到重复的ID。找到这些副本后,我必须将它们写入字符串中。到目前为止听起来很简单

students.stream()
    .filter(i-> Collections.frequency(students, i) >1)
    .forEach(System.out::println);
但是当我尝试上面的代码时,我没有打印出任何副本。我知道它不起作用,因为我没有比较学生ID,但我不知道如何比较它们

我的输出现在是空白的

学生看起来像这样:

public class Student {
    private String name;
    private int id;

    // All-args constructor, getters and setters
    // omitted for brevity
}
下面是我的示例列表:

public static ArrayList<Student> students = new ArrayList<>(Arrays.asList(
    new Student("Willi", 373583),
    new Student("Anselma", 476749),
    new Student("Noll", 345909),
    new Student("Inessa", 307055),
    new Student("Godart", 423496),
    new Student("Sissie", 393508),
    new Student("Allin", 434824),
    new Student("Catharine", 374286),
    new Student("Kore", 319004),
    new Student("Cornell", 325856),
    new Student("Mikkel", 468023),
    new Student("Ross", 383096),
    new Student("Robbie", 434105),
    new Student("Cariotta", 451072),
    new Student("Wendye", 334066),
    new Student("Janey", 494932),
    new Student("Nonna", 303659),
    new Student("Franklin", 460296),
    new Student("Kikelia", 466208),
    new Student("Jade", 497277),
    new Student("Traver", 451487),
    new Student("Alain", 304500),
    new Student("Jude", 335189),
    new Student("Gaile", 396638),
    new Student("Hilarius", 352284),
    new Student("Bengt", 463248),
    new Student("Brok", 473778),
    new Student("Keri", 345246),
    new Student("Ingar", 488058),
    new Student("Almeta", 422016),
    new Student("Hanny", 460693),
    new Student("Mattias", 337679),
    new Student("Cristabel", 356625),
    new Student("Banky", 320692),
    new Student("Karolina", 487674),
    new Student("Osmond", 397483),
    new Student("Essy", 384638),
    new Student("Katha", 320650),
    new Student("Dorey", 476369),
    new Student("Harlan", 499766),
    new Student("Jess", 416688),
    new Student("Bevon", 338526),
    new Student("Phaidra", 367390),
    new Student("Arthur", 341507),
    new Student("Krista", 318817),
    new Student("Riki", 470347)));

对于每个元素,您必须遍历学生以检查频率。更优化的版本是将其分组一次并打印重复的版本:

students.stream()
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet().stream()
    .filter(e -> e.getValue() > 1)
    .map(Map.Entry::getKey)
    .forEach(System.out::println);

对于每个元素,您必须遍历学生以检查频率。更优化的版本是将其分组一次并打印重复的版本:

students.stream()
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet().stream()
    .filter(e -> e.getValue() > 1)
    .map(Map.Entry::getKey)
    .forEach(System.out::println);

可能的解决方案之一是实现有状态谓词:

public static <T> Predicate<T> distinctByKey(
    Function<? super T, ?> keyExtractor) {

    Map<Object, Boolean> seen = new ConcurrentHashMap<>(); 
    return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; 
}
要按Id获取新的筛选集合,您可以使用:

List<Student> studentListFiltered = studentList.stream() 
  .filter(distinctByKey(s -> s.getId())) 
  .collect(Collectors.toList());

可能的解决方案之一是实现有状态谓词:

public static <T> Predicate<T> distinctByKey(
    Function<? super T, ?> keyExtractor) {

    Map<Object, Boolean> seen = new ConcurrentHashMap<>(); 
    return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; 
}
要按Id获取新的筛选集合,您可以使用:

List<Student> studentListFiltered = studentList.stream() 
  .filter(distinctByKey(s -> s.getId())) 
  .collect(Collectors.toList());

添加一个从学生处获取id的map before筛选器,然后在filter和frequencyOverride Student equals方法中使用该id来比较id或添加。mapStudent::id before filteri added.mapStudent::id但我不确定要在筛选器中写入什么,谢谢您的帮助。您能提出问题并发布学生类的定义吗?您还可以发布示例学生列表以及您希望从该示例列表中获得的输出吗?您唯一没有添加的是您希望在处理示例列表后获得的输出。在从学生获取id的筛选器之前添加一个映射,然后在筛选器和frequencyOverride Student equals方法中使用该id来比较id或添加.mapStudent::id在筛选器之前我添加了.mapStudent::id,但我不确定要在筛选器中写入什么内容,谢谢您的帮助您可以提出问题并发布学生类的定义吗?你还可以发布一个学生名单样本以及你想从该样本名单中获得的输出吗?你唯一没有添加的是你想在处理样本名单后获得的输出。好吧,我试过了,但它仍然没有打印出任何内容。将过滤器值设置为0后,它将打印出一些引用。大多数学生反对,但不反对IDs@Pody您需要重写equals和hashCode谢谢您的帮助,我对Java和Lamdas非常陌生,但您能告诉我重写equals和hashCode的方法吗?@Pody Collectors.groupingByStudent::getId。。。对于在现有代码中多次出现的代码,只打印ID是一个合适的用法。@Pody这是一个很好的方法,但是按照Naman的建议,用Student::getId替换Function.identity。好吧,我试过了,但它仍然没有打印出任何内容。将过滤器值设置为0后,它将打印出一些引用。大多数学生反对,但不反对IDs@Pody您需要重写equals和hashCode谢谢您的帮助,我对Java和Lamdas非常陌生,但您能告诉我重写equals和hashCode的方法吗?@Pody Collectors.groupingByStudent::getId。。。对于在现有代码中多次出现的代码,只打印ID是一个合适的用法。@Pody这是一个很好的方法,但是按照Naman的建议,将Function.identity替换为Student::getId。值得链接一些源代码-。但这会收集不同的学生,而不是像问题中那样打印重复的ID。值得链接一些源-。但这会收集不同的学生,而不会像问题中那样打印重复的学生ID。