Сведение Iterable‹Iterable‹T›› в Guava

Есть ли в Гуаве метод flatten или простой способ преобразовать Iterable<Iterable<T>> в Iterable<T>?

У меня есть Multimap<K, V> [sourceMultimap], и я хочу вернуть все значения, где ключ соответствует некоторому предикату [keyPredicate]. Итак, на данный момент у меня есть:

Iterable<Collection<V>> vals = Maps.filterKeys(sourceMultimap.asMap(), keyPredicate).values();

Collection<V> retColl = ...;
for (Collection<V> vs : vals) retColl.addAll(vs);
return retColl;

Я просмотрел документы Guava, но ничего не выскочило. Я просто проверяю, ничего не пропустил. В противном случае я извлеку свои три строки в короткий общий метод сглаживания и оставлю его как есть.


person Andy Whitfield    schedule 10.05.2011    source источник


Ответы (2)


метод Iterables.concat удовлетворяет этому требованию:

public static <T> Iterable<T> concat(Iterable<? extends Iterable<? extends T>> inputs)
person Sean Parsons    schedule 10.05.2011
comment
Я предполагаю, что это потому, что это конкатенация только одного уровня, а не сглаживание :) - person Gabriel Ščerbák; 10.05.2011
comment
Кроме того, если коллекция создается из преобразования гуавы, вы можете использовать FluentIterable transformAndConcat: docs.guava-libraries.googlecode.com/git/javadoc/com/google/ - person Luís Bianchin; 08.12.2014

Начиная с Java 8, вы можете сделать это без Guava. Это немного неуклюже, потому что Iterable не предоставляет потоки напрямую, требуя использования StreamSupport, но не требует создания новая коллекция, как код в вопросе.

private static <T> Iterable<T> concat(Iterable<? extends Iterable<T>> foo) {
    return () -> StreamSupport.stream(foo.spliterator(), false)
        .flatMap(i -> StreamSupport.stream(i.spliterator(), false))
        .iterator();
}
person Jeffrey Bosboom    schedule 09.01.2015
comment
Не соответствует моим потребностям, потому что мой итератор ленив, но вся лень теряется при преобразовании такого итератора в поток. - person odiszapc; 27.02.2016
comment
@odiszapc Я не понимаю, что ты имеешь в виду. Iterable.spliterator() просто возвращает Spliterator, обертывающий Iterable.iterator(); никакие элементы не рисуются до тех пор, пока не начнется терминальная операция потока. Точно так же StreamSupport.stream явно задокументирован, чтобы не начинать запрашивать разделитель до тех пор, пока не начнется операция терминала. Итак, я думаю, вы говорите, что ваш iterable верхнего уровня ленив, и вы хотите отложить вызов iterator() на нем? В этом случае используйте перегрузку StreamSupport.stream с поставщиком (StreamSupport.stream(() -> foo.spliterator(), false)). - person Jeffrey Bosboom; 28.02.2016
comment
@odiszapc В противном случае мне был бы интересен минимальный пример, показывающий, почему этот ответ не работает, если у вас есть время, чтобы сделать его, потому что я кое-что из него узнаю. - person Jeffrey Bosboom; 28.02.2016