简体   繁体   中英

Zip two lists into an immutable multimap in Java 8 with Guava?

The for loop looks like

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

A possible first step in Guava / Java 8 is

Streams.zip(keys, values, zippingFunction)

I think zippingFunction needs to return a map entry, but there isn't a publicly constructable list entry. So the "most" functional way I can write this is with a zipping function that returns a Pair, which I'm not sure exists in Guava, or returns a two-element list, which is a mutable type that does not properly connote there are exactly 2 elements.

This would be desired if I could create a map entry:

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

This seems like the best way, except it's not possible, and the zip into entries and unzip from entries still seems roundabout. Is there a way to make this possible or a way it can be improved?

If your lists are random access, you can do it without zipping:

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

I think your procedural code is the most optimal solution already (both in terms of memory and speed, assuming random access lists). With small corrections, so that your code compiles, it would be:

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

If you really want to use streams in order to "be functional", zipping two streams is the way to go, but you'd still have to create intermediate "pair" objects before collecting to multimap. You claim that "there isn't a publicly constructable list entry", but it's not true, there are JDK's SimpleImmutableEntry and Guava's Maps.immutableEntry you can use here (and they fit better than more generic Pair , which, in fact, cannot be found in both JDK or Guava.

Using Streams#zip requires passing streams, so the final code would look like this:

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

If you're open to using other "functional" Java libraries which allow more stream-related operations, you could use jOOL and its Seq.zip , which accept iterable parameters:

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

Another library would be StreamEx , which exposes EntryStream - an abstraction for key-value pair streams.

So, you almost did it right! Below is your updated code(Suppose your lists are of Integer type) :

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

But I always love to do things at the native level as it gives you more power. See code below by using 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();

Note:- builder2.putAll(builder3.build()) BiConsumer will work only when you use parallel stream. That's the behavior of collect (One of my favorite from streams).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM