【问题标题】:De-duping Java 8 streams对 Java 8 流进行重复数据删除
【发布时间】:2017-11-09 17:24:54
【问题描述】:

这里是 Java 8。我有一个方法checkDupeKeys,它将三个不同的SortedMap 实例作为其参数,并且需要验证没有两个SortedMap 实例具有相同的键。迄今为止我最好的尝试:

private void checkDupeKeys(SortedMap<String, Fizz> fizzes, SortedMap<String, Buzz> buzzes,
        SortedMap<String, Foobar> foobars) {}
    List<String> keyNames = new ArrayList<>();

    keyNames.addAll(fizzes.keySet().stream().collect(Collectors.toList()));
    keyNames.addAll(buzzes.keySet().stream().collect(Collectors.toList()));
    keyNames.addAll(foobars.keySet().stream().collect(Collectors.toList()));

    if(keyNames.size() > keyNames.stream().collect(Collectors.toSet()).size()) {
        throw new IllegalArgumentException("Duplicate key names are not allowed.");
    }
}

相信这是可行的,但是很可能有更好的方法(效率等)。

我主要担心的是这种方法不允许我识别哪些键名是重复的。理想情况下,我希望异常消息是:

Duplicate key names are not allowed. You have the following duplicate key names: (1) fizzes["derp"] and buzzes["derp"]. (2) fizzes["flim"] and foobars["flim"]. (3) buzzes["flam"] and foobars["flam"].

如何修改我的(非静态)checkDupeKeys 方法以引发符合此条件的异常?也就是说,我如何访问流中的哪些键是彼此重复的。我确信我可以使用较旧的 Java 集合 API 以困难的方式做到这一点,但在这个解决方案中,效率和利用 Java 8 API 对我来说很重要。

【问题讨论】:

标签: java collections java-8 java-stream


【解决方案1】:

没有太多使用 Java 8 的功能习语,我会简单地使用 Set#retainAll 进行每次比较(总共 3 个)。

参见下面的代码草案:

private void checkDupeKeys(SortedMap<String, Fizz> fizzes, 
    SortedMap<String, Buzz> buzzes, 
    SortedMap<String, Foobar> foobars) {

    // copies the key set
    Set<String> fizBuzSet = new HashSet<>(fizzes.keySet());

    // this removes all elements of the set that aren't present in the given key set
    fizBuzSet.retainAll(buzzes.keySet());

    // aggregating dupes if needed
    Map<String, Collection<String>> dupes = new HashMap<>();
    // flag to throw exception if needed
    boolean areThereDupes = false;

    if (!fizBuzSet.isEmpty()) {
        areThereDupes = true;
        // TODO log fizBuzSet as set of duplicates between fizzes and buzzes
        // or...
        dupes.put("Fizzes vs Buzzes", fizBuzSet);
    }
    // TODO repeat with fizzes vs foobars, then again with buzzes vs foobars

    // you can either log the dupes separately, or use a Map<String,Collection<String>> where the  
    // keys represent a compound of the two SortedMaps being compared and the values represent the actual duplicates  
    // e.g...
    if (areThereDupes) {
        // TODO throw exception with dupes map representation in message
    }

}

【讨论】:

  • 这没有做问题中想要的。请查看问题中的异常部分。
  • @nullpointer 是的,这不会引发异常,但是如果您查看评论,它确实给出了有关如何通过比较聚合重复项的建议(这实际上是 OP 想要的)。反过来,这可以作为异常消息传递,即如果地图不为空,则可能会引发地图表示的异常。
  • @nullpointer 我已经编辑以证实映射和异常抛出,希望现在更具体一点。
【解决方案2】:

您要做的第一件事是将所有密钥收集到一个流中:

 Stream<String> keys = Stream.of(
       fizzes.keySet().stream(), 
       buzzes.keySet().stream(), 
       foobars.keySet().stream())
    .flatMap(s -> s);

现在您可以将collect它们放入计数地图中:

 Map<String, Long> counts = keys.collect(
     Collectors.groupingBy(Function.identity(),
     Collectors.counting()));

您可以过滤计数> 1的条目:

 Set<String> duplicates = counts.entrySet().stream()
            .filter( e -> e.getValue() > 0)
            .map(Entry::getKey)
            .collect(Collectors.toSet());

如果此集合不为空,则抛出异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多