使用 Guava 将两个列表压缩到 Java 8 中的不可变多映射中?
Zip two lists into an immutable multimap in Java 8 with Guava?
for 循环看起来像
ImmutableListMultiMap.<Key, Value>Builder builder
= ImmutableListMultiMap.<Key, Value>newBuilder();
for (int i = 0; i < Math.min(keys.length(), values.length()); i++) {
builder.put(keys.at(i), values.at(i));
}
番石榴/Java8 可能的第一步是
Streams.zip(keys, values, zippingFunction)
我认为 zippingFunction
需要 return 地图条目,但没有可公开构建的列表条目。所以我能写的 "most" 函数式方法是使用一个压缩函数 return 是一个 Pair,我不确定它是否存在于 Guava 中,或者 return 是一个双元素列表,它是一个可变类型,不能正确表示恰好有 2 个元素。
如果我可以创建地图条目,这将是理想的:
Streams.zip(keys, values, zippingFunction)
.collect(toImmutableListMultimap(e -> e.getKey(), e.getValue())
这似乎是最好的方法,但这是不可能的,而且压缩到条目中和从条目中解压缩似乎仍然是迂回的。有没有办法使这成为可能或可以改进它?
我认为您的过程代码已经是最佳解决方案(在内存和速度方面,假设是随机访问列表)。通过小的更正,您的代码可以编译,它将是:
ImmutableListMultimap.Builder<Key, Value> builder = ImmutableListMultimap.builder();
for (int i = 0; i < Math.min(keys.size(), values.size()); i++) {
builder.put(keys.get(i), values.get(i));
}
return builder.build();
如果您真的想使用流来 "be functional",压缩两个流是可行的方法,但您仍然必须在收集到多图之前创建中间 "pair" 对象。您声称 "there isn't a publicly constructable list entry",但事实并非如此,您可以在此处使用 JDK 的 SimpleImmutableEntry
and Guava's Maps.immutableEntry
(它们比更通用的 Pair
更合适,实际上, 在 JDK 或 Guava 中都找不到。
使用Streams#zip
需要传递流,因此最终代码如下所示:
Streams.zip(keys.stream(), values.stream(), SimpleImmutableEntry::new)
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue));
如果您愿意使用其他 "functional" Java 允许更多 stream-related 操作的库,您可以使用 jOOL and its Seq.zip
,它接受可迭代的参数:
Seq.zip(keys, values, SimpleImmutableEntry::new)
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue));
另一个库是 StreamEx, which exposes EntryStream
- key-value 对流的抽象。
如果您的列表是随机访问的,则无需压缩即可:
Map<Key, Value> map = IntStream.range(0, Math.min(keys.size(), values.size()))
.boxed()
.collect(toImmutableListMultimap(i -> keys[i], i -> values[i]));
所以,你几乎做对了!以下是您更新后的代码(假设您的列表是 Integer
类型):
Streams.zip(keys.stream(), values.stream(), AbstractMap.SimpleImmutableEntry::new)
.collect(toImmutableListMultimap(Map.Entry<Integer, Integer>::getKey,
Map.Entry<Integer, Integer>::getValue)
);
但我总是喜欢在本地级别做事,因为它会给你更多的力量。使用 collect
:
查看下面的代码
Streams.zip(keys.stream(), values.stream(), (k, v) -> new AbstractMap.SimpleImmutableEntry(k, v))
.collect(ImmutableListMultimap::builder,
ImmutableListMultimap.Builder::put,
(builder2, builder3) -> builder2.putAll(builder3.build())
).build();
注意:- builder2.putAll(builder3.build())
BiConsumer 仅在使用并行流时有效。这就是 collect
(我最喜欢的流之一)的行为。
for 循环看起来像
ImmutableListMultiMap.<Key, Value>Builder builder
= ImmutableListMultiMap.<Key, Value>newBuilder();
for (int i = 0; i < Math.min(keys.length(), values.length()); i++) {
builder.put(keys.at(i), values.at(i));
}
番石榴/Java8 可能的第一步是
Streams.zip(keys, values, zippingFunction)
我认为 zippingFunction
需要 return 地图条目,但没有可公开构建的列表条目。所以我能写的 "most" 函数式方法是使用一个压缩函数 return 是一个 Pair,我不确定它是否存在于 Guava 中,或者 return 是一个双元素列表,它是一个可变类型,不能正确表示恰好有 2 个元素。
如果我可以创建地图条目,这将是理想的:
Streams.zip(keys, values, zippingFunction)
.collect(toImmutableListMultimap(e -> e.getKey(), e.getValue())
这似乎是最好的方法,但这是不可能的,而且压缩到条目中和从条目中解压缩似乎仍然是迂回的。有没有办法使这成为可能或可以改进它?
我认为您的过程代码已经是最佳解决方案(在内存和速度方面,假设是随机访问列表)。通过小的更正,您的代码可以编译,它将是:
ImmutableListMultimap.Builder<Key, Value> builder = ImmutableListMultimap.builder();
for (int i = 0; i < Math.min(keys.size(), values.size()); i++) {
builder.put(keys.get(i), values.get(i));
}
return builder.build();
如果您真的想使用流来 "be functional",压缩两个流是可行的方法,但您仍然必须在收集到多图之前创建中间 "pair" 对象。您声称 "there isn't a publicly constructable list entry",但事实并非如此,您可以在此处使用 JDK 的 SimpleImmutableEntry
and Guava's Maps.immutableEntry
(它们比更通用的 Pair
更合适,实际上, 在 JDK 或 Guava 中都找不到。
使用Streams#zip
需要传递流,因此最终代码如下所示:
Streams.zip(keys.stream(), values.stream(), SimpleImmutableEntry::new)
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue));
如果您愿意使用其他 "functional" Java 允许更多 stream-related 操作的库,您可以使用 jOOL and its Seq.zip
,它接受可迭代的参数:
Seq.zip(keys, values, SimpleImmutableEntry::new)
.collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue));
另一个库是 StreamEx, which exposes EntryStream
- key-value 对流的抽象。
如果您的列表是随机访问的,则无需压缩即可:
Map<Key, Value> map = IntStream.range(0, Math.min(keys.size(), values.size()))
.boxed()
.collect(toImmutableListMultimap(i -> keys[i], i -> values[i]));
所以,你几乎做对了!以下是您更新后的代码(假设您的列表是 Integer
类型):
Streams.zip(keys.stream(), values.stream(), AbstractMap.SimpleImmutableEntry::new)
.collect(toImmutableListMultimap(Map.Entry<Integer, Integer>::getKey,
Map.Entry<Integer, Integer>::getValue)
);
但我总是喜欢在本地级别做事,因为它会给你更多的力量。使用 collect
:
Streams.zip(keys.stream(), values.stream(), (k, v) -> new AbstractMap.SimpleImmutableEntry(k, v))
.collect(ImmutableListMultimap::builder,
ImmutableListMultimap.Builder::put,
(builder2, builder3) -> builder2.putAll(builder3.build())
).build();
注意:- builder2.putAll(builder3.build())
BiConsumer 仅在使用并行流时有效。这就是 collect
(我最喜欢的流之一)的行为。