Заархивировать два списка в неизменяемый multimap в Java 8 с помощью 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));
}

Возможным первым шагом в Guava / Java 8 является

Streams.zip(keys, values, zippingFunction)

Я думаю, что zippingFunction должен вернуть запись карты, но нет публично конструируемой записи списка. Таким образом," самый " функциональный способ, которым я могу написать это, - это функция zipping, которая возвращает пару, которая, я не уверен, существует в Guava, или возвращает список из двух элементов, который является изменяемым типом, который должным образом не означает, что есть ровно 2 элемента.

Это было бы желательно, если бы я мог создайте запись на карте:

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

Это кажется лучшим способом, за исключением того, что это невозможно, и zip в записи и распаковать из записей все еще кажется окольным путем. Есть ли способ сделать это возможным или его можно улучшить?

3 4

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

Если вы действительно хотите использовать потоки для того, чтобы" быть функциональным", сжатие двух потоков-это путь, но вам все равно придется создать промежуточные" парные " объекты, прежде чем собирать в multimap. Вы утверждаете, что" нет публично конструируемой записи списка", но это не так правда, есть JDK-ы SimpleImmutableEntry и гуава тоже Maps.immutableEntry Вы можете использовать здесь (и они подходят лучше, чем более общие Pair, которые, на самом деле, не могут быть найдены ни в JDK, ни в Guava.

Использование Streams#zip требуется передача потоков, поэтому окончательный код будет выглядеть следующим образом:

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

Если вы открыты для использования других "функциональных" библиотек Java, которые позволяют выполнять больше операций, связанных с потоком, вы можете использовать jOOL и его Seq.zip, которые принимают iterable параметры:

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

Другой библиотекой будет StreamEx , который предоставляет EntryStream - абстракция для потоков пар ключ-значение.

Если ваши списки имеют произвольный доступ, вы можете сделать это без промелькивания:

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 (Один из моих любимых потоков).