Java 8 :How to remove duplicates from the List based on multiple properties preserving the order

标签 java collections java-8 duplicates java-stream

我正在尝试从基于多个属性的学生对象列表中删除重复项,同时保留顺序,如下所示,我有学生对象列表,其中我们有多个同名学生,但出勤率不同……我需要删除重复项具有相同名称且学生出席人数为 100 的学生,同时保留顺序。

Student{studentId=1, studentName='Sam', studentAttendence=100, studentAddress='New York'}
Student{studentId=2, studentName='Sam', studentAttendence=50, studentAddress='New York'}
Student{studentId=3, studentName='Sam', studentAttendence=60, studentAddress='New York'}
Student{studentId=4, studentName='Nathan', studentAttendence=40, studentAddress='LA'}
Student{studentId=5, studentName='Ronan', studentAttendence=100, studentAddress='Atlanta'}
Student{studentId=6, studentName='Nathan', studentAttendence=100, studentAddress='LA'}
删除重复项后的期望输出:
Student{studentId=2, studentName='Sam', studentAttendence=50, studentAddress='New York'}
Student{studentId=3, studentName='Sam', studentAttendence=60, studentAddress='New York'}
Student{studentId=4, studentName='Nathan', studentAttendence=40, studentAddress='LA'}
Student{studentId=5, studentName='Ronan', studentAttendence=100, studentAddress='Atlanta'}
我现在所拥有的只是根据名称删除重复项而不考虑百分比(100)......并且也不保留顺序......非常感谢任何帮助。(学生供应商是学生名单的简单供应商功能)
studentsSupplier.get().stream()
                .sorted(Comparator.comparing(Student::getStudentName))
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(
                                () -> new TreeSet<>(Comparator.comparing(Student::getStudentName))), ArrayList::new));
注意:只有学生姓名匹配且百分比为100的重复记录必须删除,(记录Ronon有百分比100但没有重复的学生姓名相同,因此不能删除)

最佳答案

如果你想保留顺序,显然不要打电话.sorted ,这扰乱了秩序。
更普遍地在这里使用流是复杂的。如果您想对流中的每个元素执行的操作是独立的(除了正在考虑的一个元素之外,不需要查看任何内容,即不需要查看邻居),则类似流。这不是这里的情况。
如果删除任何出勤率为 100 的学生是正确的(顺便说一句,这是一个错字,正确的词是出勤),那么所有这些关于“重复”的东西都是一个红鲱鱼,你只需要:

list.removeIf(s -> s.getStudentAttendence() >= 100);
但如果想法是:仅当出席人数超过 100 人时才删除记录,列表中至少有一个其他记录具有相同的名称,它变得更加复杂。
主要问题是您的数据存储机制不适合此工作 .如果你只是停止使用 lambda,这并不难。将您的列表视为由 1 亿个条目组成会有所帮助。整个流操作将 1 亿个条目的名称保留在“内存中”显然是不可行的。你没有那么多内存。数据结构(List)也不提供任何快速查找;没有办法编写代码来回答这个问题“有多少条学生姓名记录 Sam”。是否在此列表中?)而无需遍历 1 亿个条目,这是一项非常重要的工作。
因此,考虑到以下限制:
  • 输入数据在 List形式。
  • 输入数据尚未排序。
  • 输出必须与输入保持相同的顺序。

  • 那么工作是不可能 在它的脸上!
    因此,相反,您需要接受它不是一个简单的单行程序,并且您需要首先制作存储您需要的相同数据存储的替代版本。
    然后还有其他问题。特别是,如果你有 3 Sam 会发生什么?学生和每条记录都有studentAttendence = 100 ?他们都应该被删除吗?不应该删除吗?删除 2 个任意的?
    通常,如果您在编写算法时遇到问题,实际问题是您还没有完全指定您想要的行为,因此您的挣扎主要是由于您没有完全理解问题,而不是编码问题。
    假设规则很简单:删除所有出勤率 = 100 的学生,但前提是存在出勤率低于 100 的同名记录。如果所有记录的出勤率均为 100,则保留所有记录,然后:
    List<Students> students = ...;
    Set<String> dupeNames = students.stream()
      .filter(s -> s.getAttendence() < 100)
      .map(Student::getStudentName)
      .collect(Collectors.toSet());
    
    students.removeIf(s -> s.getAttendence() < 100 && dupeNames.contains(s.getStudentName());
    
    会完成工作,并且会很快完成。 (O(n),在算法上是特定的:制作基于集合的副本需要每个学生记录的固定时间步长,因此 O(n) 和 removeIf 调用同样需要检查每个学生,但只需要执行固定时间每步工作,因为 .contains() 在集合上是恒定时间,假设良好的散列分布,字符串通常具有),因此,恒定数量的 O(n) 操作意味着整个操作是 O(n):所需的时间随输入列表中有多少学生线性增长(与每次处理列表中的单个条目时都扫描整个列表的解决方案相比,该条目随输入大小的平方增长)。

    关于Java 8 :How to remove duplicates from the List based on multiple properties preserving the order,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67299144/

    相关文章:

    java - jdk8 中本地日期的 EpochSeconds

    java - 使用 groupingBy 创建一个以不可变列表为键的 Map

    java - java8中累积对的函数式方法

    java - 如何用图像按钮替换设置项

    java - SHA256withRSA 它是做什么的,顺序是什么?

    java - 在 ArrayList 中使用泛型(Java, "cannot be applied"错误)

    java - 按特定顺序对 ArrayList 中的值进行排序

    java - 使用 Set 从 arrayList 中删除重复列表

    java - 使用手势覆盖检测 Android 字母手势

    java - 如何处理Freemarker字符串模板?