【问题标题】:Java Stream - Retrieving repeated records from CSVJava Stream - 从 CSV 检索重复记录
【发布时间】:2021-08-04 13:14:38
【问题描述】:

我搜索了该网站并没有找到类似的内容。我是使用 Java 流的新手,但我知道它是循环命令的替代品。但是,我想知道是否有一种方法可以使用流过滤 CSV 文件,如下所示,其中仅重复记录包含在结果中并按 Center 字段分组。

初始 CSV 文件

最终结果

另外,同一对不能反向出现在最终结果中,如下表所示:

这不应该发生

有没有办法同时使用流和分组,因为理论上需要两个循环来执行任务?

提前致谢。

【问题讨论】:

  • 我猜你的意思是除了 id 字段之外的其他记录,对吧?因为它使您的示例中的所有记录都不同。
  • 这些是真实姓名和生日吗?
  • 密切相关的问题/答案:stackoverflow.com/a/47226834/2513200
  • 这是一个数字,但这里的想法也适用:stackoverflow.com/a/31341963/2513200
  • @Bohemian No. 数据是假的!!!哈哈。

标签: java csv stream


【解决方案1】:

您可以在 O(n) 效率下以流的形式一次性完成:

class PersonKey {
    // have a field for every column that is used to detect duplicates
    String center, name, mother, birthdate;
    public PersonKey(String line) {
        // implement String constructor
    }
    // implement equals and hashCode using all fields
}

List<String> lines; // the input 
Set<PersonKey> seen = new HashSet<>();
List<String> unique = lines.stream()
  .filter(p -> !seen.add(new PersonKey(p))
  .distinct()
  .collect(toList());

这里的技巧是 HashSet 具有恒定时间操作,如果要添加的值已经在集合中,则其 add() 方法返回 false,否则返回 true。

【讨论】:

  • +1 虽然就个人而言,如果我必须在流中使用 2 个有状态过滤器,我更喜欢循环。如果我没记错的话,found-Set 如果我们可以忍受例如LinkedHashSet-result 而不是列表。
  • @hulk 你错了:) 问题是集合中收集的对象不是结果中需要的对象。您可以通过在映射到其 equals 方法忽略其 id 字段的对象后使用 distinct 来避免第二组,这违反了所有好事。但是内部 distinct 无论如何都使用 HashSet,所以这段代码并不重——你只是看到了集合。不需要 LinkedHashSet - 无论哪种方式总是找到第一个唯一的项目。
  • 啊,我明白了,我确实错过了。那么,这可能是最好的:)
  • 您可以使用 csv 驱动程序将其作为 sql 查询运行
  • @Bohemian 我认为我的表达不正确。我需要知道的是哪些记录重复的列表,而不仅仅是它们是否重复。所以我认为使用 hashset 并不能解决问题。顺便说一句,非常感谢您的回复。
【解决方案2】:

我从您的示例中了解到,如果除 ID 之外的所有属性都具有相同的值,则您认为该条目是重复的。您可以为此使用anymatch

list.stream().filter(x ->
                list.stream().anyMatch(y -> isDuplicate(x, y))).collect(Collectors.toList())

那么 isDuplicate(x,y) 有什么作用呢?

这会返回一个boolean。您可以在此方法中检查除 id 之外的所有条目是否具有相同的值:

private boolean isDuplicate(CsvEntry x, CsvEntry y) {
    return !x.getId().equals(y.getId())
            && x.getName().equals(y.getName())
            && x.getMother().equals(y.getMother())
            && x.getBirth().equals(y.getBirth());
}

我假设您已将所有条目都设为String。根据类型更改检查。这将为您提供重复的条目及其对应的ID

【讨论】:

  • 这不是一个有效的解决方案。
  • 想过使用哈希集,但这不会给出 OP 的要求
  • 它可以,使用正确的元素类型(使用适当的equals 方法)。或带有自定义ComparatorTreeSet
  • @devReddit 嗨...非常感谢您的回复。你是对的:hashset 不能解决我的问题。顺便说一句,为了能够对结果进行分组,是否有必要获取上面的结果流并将一个组应用于选择,对吗?不能在同一个命令中分组?
  • @AdalbertoJoséBrasaca 您可以使用Collectors.groupingBy(Function&lt;? super T,? extends K&gt; classifier) 根据流的collect() 中的特定属性对结果进行分组。
猜你喜欢
  • 2022-07-07
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 1970-01-01
  • 2012-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多