使用Guava将两个列表压缩到Java 8中的不可变多图中?

时间:2018-03-13 16:59:02

标签: java java-8 functional-programming guava multimap

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));
}

Guava / Java 8中可能的第一步是

Streams.zip(keys, values, zippingFunction)

我认为zippingFunction需要返回一个映射条目,但是没有可公开构建的列表条目。因此,我可以编写的“最”功能方式是使用压缩函数返回一个Pair,我不确定它是否存在于Guava中,或者返回一个两元素列表,这是一个可变类型,在那里没有正确地说明正好是2个元素。

如果我可以创建一个地图条目,那将是理想的:

Streams.zip(keys, values, zippingFunction)
.collect(toImmutableListMultimap(e -> e.getKey(), e.getValue())

这似乎是最好的方式,除非它不可能,并且拉入条目并从条目解压缩仍然看起来很迂回。有没有办法使这成为可能或一种可以改进的方式?

3 个答案:

答案 0 :(得分:5)

如果你的列表是随机访问的,你可以不用压缩来实现:

Map<Key, Value> map = IntStream.range(0, Math.min(keys.size(), values.size()))
    .boxed()
    .collect(toImmutableListMultimap(i -> keys[i], i -> values[i]));

答案 1 :(得分:3)

我认为你的程序代码已经是最优的解决方案(在内存和速度方面,假设随机访问列表)。通过小的修正,以便您的代码编译,它将是:

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();

如果你真的想要使用流来实现功能&#34;,那么就可以使用两个流,但是你还需要创建中间&#34;对&#34; ;收集到multimap之前的对象。您声称&#34;没有可公开构建的列表条目&#34;,但它不是真的,有JDK&#39; s SimpleImmutableEntry和Guava&#39; s {{ 3}}你可以在这里使用(它们比更通用的Pair更合适,事实上,它们在JDK或Guava中都找不到。

使用Maps.immutableEntry需要传递流,因此最终代码如下所示:

Streams.zip(keys.stream(), values.stream(), SimpleImmutableEntry::new)
    .collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue));

如果您愿意使用其他&#34;功能性&#34;允许更多与流相关的操作的Java库,您可以使用Streams#zip及其jOOL,它们接受可迭代的参数:

    Seq.zip(keys, values, SimpleImmutableEntry::new)
        .collect(toImmutableListMultimap(Map.Entry::getKey, Map.Entry::getValue));

另一个库是Seq.zip,它公开了StreamEx - 键值对流的抽象。

答案 2 :(得分:2)

所以,你几乎做对了!以下是您的更新代码(假设您的列表属于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的行为(我最喜欢的一个来自溪流)。