如何使用 lambda 正确制作多级地图?
How can I properly make a multilevel map using lambdas?
我正在使用 JCIFS 比较文件夹(接受者和发送者)中的文件。在比较过程中可能会出现两种情况:
- 接受者处不存在文件
- 文件存在于接受者
我需要一张地图,其中比较的文件按上述两种类型分组,因此我可以复制不存在的文件或检查现有文件的大小和修改日期...
我想用 lambda 和流来实现,因为我会在不久的将来使用并行流,而且它也很方便...\
我已经设法制作了一个工作原型方法来检查文件是否存在并创建一个地图:
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));
}
但我无法按地图值添加更高级别的分组...
我有这样一段无法工作的代码:
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 正确吗?
P.S。来自方法参数的数组是 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);
我已经设法解决了我的问题。我的类型不匹配,所以工作代码是:
private Map<Boolean, 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(collectingAndThen(
groupingBy(Map.Entry::getValue, toMap(Map.Entry::getKey, Map.Entry::getValue)),
Collections::<Boolean, Map<String, Boolean>> unmodifiableMap));
}
收集到具有相同值的嵌套映射,不是很有用。结果 Map<Boolean, Map<String, Boolean>>
只能有两个键,true
和 false
。当你在上面调用 get(true)
时,你会得到一个 Map<String, Boolean>
,其中所有字符串键冗余映射到 true
。同样,get(false)
会给出一个你的地图,其中所有值都是 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
,反之亦然。
partitioningBy
是 groupingBy
针对 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
的每个元素完成,将不依赖于 [= 的大小30=] 了。
我正在使用 JCIFS 比较文件夹(接受者和发送者)中的文件。在比较过程中可能会出现两种情况: - 接受者处不存在文件 - 文件存在于接受者
我需要一张地图,其中比较的文件按上述两种类型分组,因此我可以复制不存在的文件或检查现有文件的大小和修改日期...
我想用 lambda 和流来实现,因为我会在不久的将来使用并行流,而且它也很方便...\
我已经设法制作了一个工作原型方法来检查文件是否存在并创建一个地图:
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));
}
但我无法按地图值添加更高级别的分组...
我有这样一段无法工作的代码:
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 正确吗?
P.S。来自方法参数的数组是 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);
我已经设法解决了我的问题。我的类型不匹配,所以工作代码是:
private Map<Boolean, 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(collectingAndThen(
groupingBy(Map.Entry::getValue, toMap(Map.Entry::getKey, Map.Entry::getValue)),
Collections::<Boolean, Map<String, Boolean>> unmodifiableMap));
}
收集到具有相同值的嵌套映射,不是很有用。结果 Map<Boolean, Map<String, Boolean>>
只能有两个键,true
和 false
。当你在上面调用 get(true)
时,你会得到一个 Map<String, Boolean>
,其中所有字符串键冗余映射到 true
。同样,get(false)
会给出一个你的地图,其中所有值都是 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
,反之亦然。
partitioningBy
是 groupingBy
针对 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
的每个元素完成,将不依赖于 [= 的大小30=] 了。