微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Java 中检查 List<CSVRecord> 是否有重复项的最简单方法

如何解决在 Java 中检查 List<CSVRecord> 是否有重复项的最简单方法

如果从 org.apache.commons.csv 传入的 CSVRecord 对象列表至少有一个重复记录,我想创建一个返回 bool 的函数

public static boolean hasDuplicate(List<CSVRecord> csvRecords){
    //...
}

到目前为止,我已经尝试从输入中创建一个集合,希望得到一个没有重复值的集合,然后我可以将大小与原始列表进行比较,但 Set 没有消除重复项。

    Set<CSVRecord> unique = new HashSet<CSVRecord>(csvRecords);

这是因为 CSVRecords 对 .csv 中的每一行都有唯一的记录编号,但我只关心比较值。所以下面我会认为记录 2 和 3 是重复的,并且会返回 true。

CSVRecord [comment='null',recordNumber=1,values=[BOB,JACKSON]]
CSVRecord [comment='null',recordNumber=2,values=[JANE,DOE]]
CSVRecord [comment='null',recordNumber=3,DOE]]

有没有一种有效的方法来检查 List 是否有基于值的重复项,而无需遍历每个条目、获取值并存储它们? 我希望该方法能够处理任何 CSVRecord,而不管值列表的形状如何。

解决方法

  public boolean hasDuplicate(List<CSVRecord> csvRecords){
    return csvRecords.size() == Set.of(csvRecords.stream().map(this::stringify)).size();
  }

  private String stringify(CSVRecord item) {
    return String.join(",",item.toMap().values());
  }
,

将整个列表放入集合中并比较大小是非常低效的。懒惰地这样做会好得多:

public static boolean hasDuplicate(List<CSVRecord> csvRecords) {
  Set<List<String>> set = new HashSet<>();
  for (CSVRecord rec : csvRecords) {
    List<String> lst = new ArrayList<>();
    for (String str : rec) lst.add(str);
    if (!set.add(lst)) return true; // add returns false if the entry is present
  }
  return false;
}

不幸的是,CSVRecord 类中的 String 数组没有公共访问权限,所以我们要么使用迭代器复制它,要么通过反射直接访问。实际上,还有第三种也是最有效的方法。如果我们为我们的类所基于的包提供与 CSVRecord 的包相同的名称,那么它的包私有方法 values() 变得可用。然后我们使用 Arrays.asList() 包装返回的数组(它不复制内容,只保存对原始数组的引用)以受益于返回列表的 equals() 方法,因此,能够将其放入设置:

package org.apache.commons.csv;

import java.util.*;

public class CSVRecordUtils {
  public static boolean hasDuplicate(List<CSVRecord> csvRecords) {
    Set<List<String>> set = new HashSet<>();
    for (CSVRecord rec : csvRecords) {
      if (!set.add(Arrays.asList(rec.values()))) {
        return true;
      }
    }
    return false;
  }
}
,
public static boolean hasDuplicate(List<CSVRecord> csvRecords){
    // create list of Maps where each map is one csvRecord's values
    List<Map<String,String>> recordsMaps = new ArrayList<>();
    // add records to the list of Maps
    for(CSVRecord record : csvRecords){
        recordsMaps.add(record.toMap());
    }
    // create set to hold unique records
    Set<Map<String,String>> unique = new HashSet<>();
    // add each map in recordsMaps to set. if the map already exists it won't be added
    for(Map<String,String> map : recordsMaps){
        unique.add(map);
    }

    boolean hasDuplicate = recordsMaps.size() != unique.size();
    return hasDuplicate;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。