如何从列表中获取仅重复对象的列表

时间:2019-07-16 07:59:15

标签: java collections java-stream

如何从列表中获取仅重复对象的列表。

我有一个对象的ArrayList

Pojo Class
Class Abc {
int id ;
String name;
Date startDate;
int rowNum;
......
}

Example Data:
id    name      startDate    rowNum
110   Art       01-Jan-2018   1
120   Art       01-Jan-2019   1
121   Science   01-Jan-2018   2
122   Computer  01-Jan-2018   3
..
190   Math      01-May-2020   40
180   Math      04-Aug-2040   40
456   Math      01-Dec-2060   40

Abc列表有时包含-4000条或更多记录。 我想在单独的列表中获取重复的rowNum的ID,名称,startDate。

Ex: List2 should contains (duplicate records only)
id    name      startDate    rowNum
110   Art       01-Jan-2018   1
120   Art       01-Jan-2019   1
.....
190   Math      01-May-2020   40
180   Math      04-Aug-2040   40
456   Math      01-Dec-2060   40

如何从列表中获取仅重复对象的列表。

2 个答案:

答案 0 :(得分:1)

  1. 按行编号(在Map<Integer,List<Abc>>中分组元素
  2. 对于每行num,保留列表大小为>= 2的列表元素
  3. 收集已过滤/保留的元素

它将给出类似如下的代码:

List<Abc> abcList = ...;

Map<Integer,List<Abc>> elementsByRowNum =
abcList.stream()
       .collect(groupingBy(Abc::getRowNum));

List<Abc> abcWithDupList = 
elementsByRowNum.values().stream()
               .filter(v-> v.size()>=2)
               .flatMap(List::stream)
               .collect(toList());

您也可以用更紧凑的方式(没有地图)来写:

List<Abc> abcWithDupList = 
abcList.stream()
       .collect(groupingBy(Abc::getRowNum))
       .values()
       .stream()  // Stream<List<Abc>>
       .filter(l-> l.size()>=2)
       .flatMap(List::stream)
       .collect(toList());

答案 1 :(得分:1)

平等不是普遍的操作,存在许多检查两个元素是否相等的方法。这就是明确注入equality定义的原因。

另一方面,您的问题是开放的,可以检索所有个重复元素或仅其中一个。

如果只需要其中一个,则Set操作是解决该问题的通用解决方案。

使用 Java ,不存在设置自定义比较器的标准方法,但是您可以使用流:

xs.stream()
    .collect(groupingBy(youCustomKey, minBy((a, b) -> 0)))
    .values().stream().map(Optional::get).collect(toList())

在这里,每个重复的组只有一个(包括单例元素!)。

如果您希望yourCustomKey下的所有重复元素都可以

xs.stream()
    .collect(groupingBy(yourCustomKey, toList()))
    .values().stream()
    .filter(x -> x.size() > 1)
    .flatMap(Collection::stream)
    .collect(toList())

在这里,您得到所有​​重复的元素。

在两种情况下,您都可以设置自定义yourCustomKey,因为您说的是“重复项应基于rowNum” ,然后

Function<Abc, Integer> yourCustomKey = Abc::getRowNum;

(显然您可以避免使用该定义)。

作为使用字符串的示例:

List<String> xs = asList("aaa", "bb", "rrr", "ff", "qqqq");

List<String> ys1 = xs.stream()
        .collect(groupingBy(String::length, minBy((a, b) -> 0)))
        .values().stream().map(Optional::get).collect(toList());

List<String> ys2 = xs.stream()
        .collect(groupingBy(String::length, toList()))
        .values().stream()
        .filter(x -> x.size() > 1)
        .flatMap(Collection::stream)
        .collect(toList());

System.out.printf("ys1: %s%n", String.join(", ", ys1));
System.out.printf("ys2: %s%n", String.join(", ", ys2));

返回:

ys1: bb, aaa, qqqq
ys2: bb, ff, aaa, rrr