如何识别列表中的重复记录?

How to identify duplicate records in a list?

我有以下问题:

我想根据注册字段是否相同从 Vo 列表中删除重复数据,我向您展示我正在尝试的解决方案。那么这是我正在制作的列表中的数据

List<MyVo> dataList = new ArrayList<MyVo>();

MyVo  data1 = new MyVo();
data1.setValidated(1);
data1.setName("Fernando");
data1.setRegistered("008982");

MyVo data2 = new MyVo();
data2.setValidated(0);
data2.setName("Orlando");
data2.setRegistered("008986");

MyVo data3 = new MyVo();
data3.setValidated(1);
data3.setName("Magda");
data3.setRegistered("008982");


MyVo data4 = new MyVo();
data4.setValidated(1);
data4.setName("Jess");
data4.setRegistered("006782");

dataList.add(data1);
dataList.add(data2);
dataList.add(data3);
dataList.add(data4);

我必须做的第一件事是根据数据是否经过验证将其分成两个不同的列表,为此注册的验证值。

List<MyVo> registeredBusinesses = new ArrayList<MyVo>();
List<MyVo> unregisteredBusinesses = new ArrayList<MyVo>();

for (MyVo map : dataList) {
    if (map.getValidated == 0) {
        unregisteredBusinesses.add(map);
    }else {
        registeredBusinesses.add(map);
    }
}

现在是注册企业列表我想从其注册字段中删除以相同值重复的数据并创建一个新列表。这就是它所需要的,但它不能正常工作

List<MyVo> duplicateList = registeredBusinesses.stream().filter(distictByRegistered(MyVo::getRegistered)).collect(Collectors.toList());


public static <T> Predicate<T> distictByRegistered(Function<?      super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

但是使用这种方法我得到以下输出:

{["验证":1,"姓名":"费尔南多","注册":"008982"], ["validated":1,"name":"Jess","re​​gistered":"006782"]}

我想要获得的输出如下:

未注册企业列表:

{["validated":0,"name":"Orlando","registered":"008986"]}

已注册企业列表:

{["validated":1,"name":"Jess","registered":"006782"]}

registeredDuplicateBusinesses 列表:

{["validated":1,"name":"Fernando","registered":"008982"], 
["validated":1,"name":"Magda","registered":"008982"]}

我不知道该怎么做,你能帮我吗?我想使用 lambdas 来减少代码,例如当我分成两个列表时的第一个代码

您的方法看起来几乎是正确的,按 Function.identity() 分组将正确标记重复项(基于 equals() 实现!),如果您有,您也可以按对象中的唯一 property/id 分组第一,您缺少的是操纵生成的地图以获取包含所有重复项的列表。我添加了描述这里发生的事情的评论。

List<MyVo> duplicateList = registeredBusinesses.stream()
    .collect(Collectors.groupingBy(Function.identity()))
    .entrySet()
    .stream()
    .filter(e -> e.getValue().size() > 1) //this is a stream of Map.Entry<MyVo, List<MyVo>>, then we want to check value.size() > 1
    .map(Map.Entry::getValue) //We convert this into a Stream<List<MyVo>>
    .flatMap(Collection::stream) //Now we want to have all duplicates in the same stream, so we flatMap it using Collections::stream
    .collect(Collectors.toList()); //On this stage we have a Stream<MyVo> with all duplicates, so we can collect it to a list.

此外,您还可以使用流 API 将 dataList 拆分为已注册和未注册。

首先我们在MyVo

中创建一个方法isUnregistered
public boolean isUnregistered() {
  return getrRegistered() == 0;
}

然后

Map<Boolean, List<MyVo>> registeredMap = dataList.stream().collect(Collectors.groupingBy(MyVo::isUnregistered));

其中 map.get(true) 将是 unregisteredBusinessesmap.get(false) registeredBusinesses

熟悉 Collectors.partitioningBy 的概念将有助于您进一步解决问题。您当前的要求中有两个地方可能暗示它。

  1. 您正在寻找 registeredunregistered 企业。在这里,您可以选择将属性实现为 boolean isRegistered,而不是使用 01,例如 0 是 false,1 是 true 往前走。您现有的带有 if-else 的代码可以重写为:

    Map<Boolean, List<MyVo>> partitionBasedOnRegistered = dataList.stream()
             .collect(Collectors.partitioningBy(MyVo::isRegistered));
    List<MyVo> unregisteredBusinesses = partitionBasedOnRegistered.get(Boolean.FALSE); // here
    List<MyVo> registeredBusinesses = partitionBasedOnRegistered.get(Boolean.TRUE);
    
  2. 尝试根据注册号 groupBy registered 企业后(尽管 identity),您需要重复的元素和这也是独一无二的。实际上是所有条目,但再次分为两个桶,即一个值大小为 == 1,另一个值大小为 > 1。由于分组将确保每个键至少对应一个元素,因此您可以使用附加映射收集所需的输出。

    Map<String, List<MyVo>> groupByRegistrationNumber = // group registered businesses by number
    
    Map<Boolean, List<List<MyVo>>> partitionBasedOnDuplicates = groupByRegistrationNumber
             .entrySet().stream()
             .collect(Collectors.partitioningBy(e -> e.getValue().size() > 1,
                     Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
    

    如果您访问上述地图的 FALSE 值,那将为您提供 groupedRegisteredUniqueBusiness,另一方面,针对 TRUE 键的值将为您提供 groupedRegisteredDuplicateBusiness.

请注意,如果您要 展平 这个 List<List<MyVo> 以获得 List<MyVo> 作为输出,您还可以利用 具有 JDK 内置实现 Java-9 及更高版本。

您正在寻找已注册和未注册的企业。在这里,您可以选择将属性实现为布尔值 isRegistered,而不是使用 0 和 1,例如 0 为假,1 为真。您现有的带有 if-else 的代码可以重写为:

Map<Boolean, List<MyVo>> partitionBasedOnRegistered = dataList.stream()
         .collect(Collectors.partitioningBy(MyVo::isRegistered));
List<MyVo> unregisteredBusinesses = partitionBasedOnRegistered.get(Boolean.FALSE); // here
List<MyVo> registeredBusinesses = partitionBasedOnRegistered.get(Boolean.TRUE);