java - 如何使用 lambda 正确制作多级 map ?

标签 java lambda java-stream collectors

我正在使用 JCIFS 比较文件夹(接受者和发送者)中的文件。在比较过程中可能会出现两种情况: - 接受者处不存在文件 - 文件存在于接受者

我需要一张 map ,其中比较的文件按提到的两种类型分组,因此我可以复制不存在的文件或检查现有文件的大小和修改日期......

我想使用 lambda 和流来实现它,因为我将在不久的将来使用并行流,而且它也很方便...\

我已经设法制作了一个工作原型(prototype)方法来检查文件是否存在并创建一个 map :

    private Map<String, Boolean> compareFiles(String[] acceptor, String[] sender) {

        return Arrays.stream(sender)
                .map(s -> new AbstractMap.SimpleEntry<>(s, Stream.of(acceptor).anyMatch(s::equals)))
Map.Entry::getValue)));
                .collect(collectingAndThen(
                        toMap(Map.Entry::getKey, Map.Entry::getValue),
                        Collections::<String,Boolean> unmodifiableMap));
    }

但我无法按 map 值添加更高级别的分组...

我有这样一段无法工作的代码:

    private Map<String, Boolean> compareFiles(String[] acceptor, String[] sender) {

        return Arrays.stream(sender)
                .map(s -> new AbstractMap.SimpleEntry<>(s, Stream.of(acceptor).anyMatch(s::equals)))
                .collect(groupingBy(
                        Map.Entry::getValue,
                        groupingBy(Map.Entry::getKey, Map.Entry::getValue)));
    }
}

我的代码无法编译,因为我遗漏了一些非常重要的东西。谁能帮我解释一下如何使这个 lambda 正确吗?

附言来自方法参数的数组是 SmbFiles samba 目录:

private final String master = "smb://192.168.1.118/mastershare/";
private final String node = "smb://192.168.1.118/nodeshare/";

SmbFile masterDir   = new SmbFile(master);
SmbFile nodeDir     = new SmbFile(node);

Map<Boolean, <Map<String, Boolean>>> resultingMap = compareFiles(masterDir, nodeDir);

最佳答案

收集到具有相同值的嵌套映射,不是很有用。结果 Map<Boolean, Map<String, Boolean>>只能有两个键,truefalse .当您调用 get(true)在上面,你会得到一个 Map<String, Boolean>其中所有字符串键冗余映射到 true .同样,get(false)会给你一张 map ,其中所有值都是 false .

对我来说,看起来你真的想要

private Map<Boolean, Set<String>> compareFiles(String[] acceptor, String[] sender) {
    return Arrays.stream(sender)
        .collect(partitioningBy(Arrays.asList(acceptor)::contains, toSet()));
}

哪里get(true)为您提供一组所有字符串,其中谓词评估为 true反之亦然。

partitioningBygroupingBy 的优化版本对于 boolean键。

请注意 Stream.of(acceptor).anyMatch(s::equals)是对 Stream 特性的过度使用。 Arrays(acceptor).contains(s)更简单,当用作谓词时 Arrays.asList(acceptor)::contains , 表达式 Arrays.asList(acceptor)将只被评估一次,一个函数调用 contains每次评估都会传递给收集器。

acceptor变大,不应该考虑并行处理,而是用散列查找代替线性查找

private Map<Boolean, Set<String>> compareFiles(String[] acceptor, String[] sender) {
    return Arrays.stream(sender)
        .collect(partitioningBy(new HashSet<>(Arrays.asList(acceptor))::contains, toSet()));
}

再次,new HashSet<>(Arrays.asList(acceptor))的准备工作只完成一次,而 contains调用,为 sender 的每个元素完成, 将不依赖于 acceptor 的大小不再。

关于java - 如何使用 lambda 正确制作多级 map ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57199656/

相关文章:

java - 如何使可运行程序提前终止

java - 如何在eclipse插件中使用ElementTreeSelectionDialog

java - 链接来自不同 fxml 文件的内容

java - JavaFX8 中使用 FXML 的 Lambda 函数

c# - 使用 MVC5 实现 HiddenForEach 时如何构造 lambda 表达式

c++ - 如何将函数的指针从std::function传递给Linux克隆?

java - 如果过滤器为 false,如何返回整个列表

Java 将 List<String> 转换为 Map<String, String>

java - 分解代码,唯一的区别是流减少操作

java - 当屏幕上存在两个完全相同的图像时,如何使用 Sikuli 和 java 从屏幕上单击图像