Iterableをコレクションに変換する簡単な方法


424

私のアプリケーションでは、サードパーティのライブラリを使用しています(正確には、MongoDBの春のデータ)。

このライブラリのメソッドは戻りますがIterable<T>、残りのコードは期待していCollection<T>ます。

すぐに一方をもう一方に変換できるユーティリティメソッドはありますか?foreachこのような単純なことのために、コード内に多数のループを作成することは避けたいと思います。


3
いずれにしても、操作を実行するためのユーティリティメソッドはコレクションの反復にバインドされるため、パフォーマンスの向上は期待できません。しかし、構文糖を探しているだけなら、GuavaまたはおそらくApacheコレクションに行きます。
Sebastian Ganslandt 2011年

とにかくコレクションの反復処理にバインドされています」、-いいえ、そうではありません。詳細については、私の回答を参照してください。
aioobe 2011年

3
特定のユースケースでは、Iterable <T>の代わりにCollection <T> / List <T> / Set <T>(必要に応じて)を返すメソッドを使用して、独自のインターフェースでCrudRepositoryを拡張できます
Kevin Van Dyck

回答:


387

グァバを使用できLists.newArrayList(反復処理可能)またはSets.newHashSet(反復処理可能)を他の同様の方法の中で、。もちろん、これはすべての要素をメモリにコピーします。それが受け入れられない場合は、これらのコードで動作するコードは、Iterableではなくを使用する必要がありCollectionます。グアバはまた、上のあなたができることをやってするのに便利な方法を提供するためにたまたまCollection使用してIterable(例えばIterables.isEmpty(Iterable)またはIterables.contains(Iterable, Object))が、パフォーマンスへの影響はより明白です。


1
すべての要素を直接反復しますか?すなわち、あるLists.newArrayList(Iterable).clear()線状または一定時間操作が?
aioobe 2011年

2
@aioobe:イテラブルのコピーを作成します。ビューが望ましいことは明記されておらず、上のほとんどのメソッドCollectionはのビューに実装できないかIterable、効率的ではないため、それを行うことはあまり意味がありません。
ColinD 2011年

@ColinDビューが必要な場合はどうなりますか?実際には、ソースコレクションに別の要素を追加した結果であるコレクションビューが必要です。私は使用できますIterables.concat()Iterable、それはCollection:( ではなく)を与えます
Hendy Irawan '10

1
これは私の質問です:stackoverflow.com/questions/4896662/…。残念ながら、問題を解決しない単純な答えはを使用することIterables.concat()です。はるかに長い答えが得られCollectionます...なぜこれがより一般的にサポートされていないのでしょうか?
ヘンディイラワン2014年

365

JDK 8以降では、追加のライブラリを使用しません。

Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);

編集:上記はのためのものIteratorです。あなたが扱っているならIterable

iterable.forEach(target::add);

86
またはiterable.forEach(target::add);
頭足類

92

このための独自のユーティリティメソッドを作成することもできます。

public static <E> Collection<E> makeCollection(Iterable<E> iter) {
    Collection<E> list = new ArrayList<E>();
    for (E item : iter) {
        list.add(item);
    }
    return list;
}

33
+1からIterableへの移行Collectionが唯一の懸念事項である場合、私は、大規模なサードパーティのコレクションライブラリをインポートするよりも、このアプローチの方を好みます。
aioobe

2
4行の関数コードは、99%が未使用になる2 MBのコンパイル済みライブラリコードよりもはるかに望ましいです。別のコストがあります。ライセンスの複雑化です。Apache 2.0ライセンスは柔軟ですが、いくつかの面倒な義務がないわけではありません。理想的には、これらの一般的なパターンの一部がJavaランタイムライブラリに直接統合されていることがわかります。
Jonathan Neufeld

2
もう1つ、とにかくArrayListを使用しているので、代わりに共変リスト型を単に使用しないのはなぜですか。これにより、ダウンキャストしたり再構成したりせずに、より多くのコントラクトを満たすことができます。Javaはいずれにせよ、型の下限をサポートしていません。
ジョナサンノイフェルド2015年

@JonathanNeufeldまたはなぜ先に進んでArrayList <T>を返さないのですか?
フアン

5
@Juanそれは非常にではありませんのでSOLID。ArrayListは、単一の責任と依存関係の逆転の原則に違反している可能性が最も高い(YAGNI)実装の詳細を公開します。完全にSOLIDのままである一方で、コレクションよりも少し多くを公開しているので、私はそれをリストのままにします。INVOKEVIRTUALに対するopcode INVOKEINTERFACEのJVMパフォーマンスへの影響が心配な場合は、多くのベンチマークから、スリープを失う価値がないことがわかります。
ジョナサンノイフェルド

80

を使用したJava 8による簡潔なソリューションjava.util.stream

public static <T> List<T> toList(final Iterable<T> iterable) {
    return StreamSupport.stream(iterable.spliterator(), false)
                        .collect(Collectors.toList());
}

1
このアプローチはIteratorUtilscommons-collections
Alex Burdusel

3
どれくらい遅い?IteratorUtils.toList()Java 5より前の方法でイテレータを使用して、新しく作成したリストに要素を1つずつ追加します。シンプルでおそらく最速ですが、バイナリに734 kBが追加されます。この方法が最善であるとわかった場合は、自分でこれを行うことができます。
xehpuk

8
最初の方が速い場合もあれば、2番目の方が速い場合もあると結論付けて、基本的なベンチマークを実行しました。ベンチマークを見せてください。
xehpuk

この問題は、新しく受け入れられた答えになる可能性があります-過剰なライブラリ(Guavaなど)を回避するのは良いことです。
java-addict301

48

IteratorUtilsfrom commons-collectionsが役立つ場合があります(ただし、最新の安定したバージョン3.2.1ではジェネリックをサポートしていません)。

@SuppressWarnings("unchecked")
Collection<Type> list = IteratorUtils.toList(iterable.iterator());

バージョン4.0(現時点ではSNAPSHOTにあります)はジェネリックをサポートしており、を取り除くことができます@SuppressWarnings

更新:CactoosIterableAsListから確認してください


5
しかし、これにはIterableではなくIteratorが必要です
hithwen

5
@hithwen、わかりません-Iterableはイテレータを提供します(回答で詳しく説明されています)-問題は何ですか?
トム

私が何を考えていたかわからない^^ U
hithwen

2
4.1以降にIterableUtils.toList(Iterable)は、便利なメソッドでありIteratorUtils、内部で使用するもありますが、(とは異なりIteratorUtils.toList)nullセーフでもあります。
Yoory N.

21

CollectionUtilsから:

List<T> targetCollection = new ArrayList<T>();
CollectionUtils.addAll(targetCollection, iterable.iterator())

このユーティリティメソッドの完全なソースは次のとおりです。

public static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
    while (iterator.hasNext()) {
        collection.add(iterator.next());
    }
}

すべての要素を直接反復しますか?すなわち、あるLists.newArrayList(someIterable).clear()線状または一定時間操作が?
aioobe

addAll名前が示すように、のソースコードを追加しました。イテレータの値を次々にコピーします。ビューではなくコピーを作成します。
Tomasz Nurkiewicz 2011年

CollectionUtils追加の行でコレクションの作成をスキップする方法がないのは残念です。
Karl Richter、


14

その間、すべてのコレクションが有限であることを忘れないでください。一方、Iterableにはまったく約束がありません。何かがIterableであれば、イテレーターを取得できます。

for (piece : sthIterable){
..........
}

次のように展開されます:

Iterator it = sthIterable.iterator();
while (it.hasNext()){
    piece = it.next();
..........
}

it.hasNext()がfalseを返す必要はありません。したがって、一般的なケースでは、すべてのIterableをコレクションに変換できるとは期待できません。たとえば、すべての正の自然数を反復処理したり、同じ結果を繰り返し生成するサイクルがあるものを反復処理したりできます。

それ以外の場合:Atreyの答えはかなり問題ありません。


1
実際に/実際のコードで、誰かが実際に無限の何かを反復するIterableに出くわしたことはありますか?私はそのようなIterableが多くの場所で痛みと苦痛を引き起こすと思います... :)
デビッド

2
@David実稼働コードでは、無限イテレーターを具体的に指すことはできませんが、それらが発生する可能性のあるケースを考えることができます。ビデオゲームには、上記の回答が示唆する周期的なパターンでアイテムを作成するスキルがある場合があります。私は無限のイテレータに出会ったことはありませんが、メモリが真の問題であるイテレータに出会ったことは間違いありません。ディスク上のファイルに対してイテレータがあります。フル1TBのディスクと4GBのRAMがある場合、メモリを使い果たしてイテレータをコレクションに変換するのは簡単です。
急進ワード101 2015

14

FluentIterable.from(myIterable).toList()たくさん使っています。


9
それもグアバからのものであることに注意すべきです。
Vadzim

またはorg.apache.commons.collections4から。それはFluentIterable.of(myIterable).toList()です
du-it

9

これはあなたの質問に対する答えではありませんが、私はそれがあなたの問題の解決策であると信じています。このインターフェースにorg.springframework.data.repository.CrudRepositoryは確かに戻るメソッドjava.lang.Iterableがありますが、このインターフェースは使用しないでください。代わりに、サブインターフェースを使用してくださいorg.springframework.data.mongodb.repository.MongoRepository。このインターフェイスには、タイプのオブジェクトを返すメソッドがありますjava.util.List


2
コードを具体的な実装にバインドすることを避けるために、汎用的なCrudRepositoryの使用を促進します。
stanlick、2015年

7

カスタムユーティリティを使用して、可能であれば既存のコレクションをキャストします。

メイン:

public static <T> Collection<T> toCollection(Iterable<T> iterable) {
    if (iterable instanceof Collection) {
        return (Collection<T>) iterable;
    } else {
        return Lists.newArrayList(iterable);
    }
}

上記ではImmutableListを使用するのが理想的ですが、ImmutableCollectionではnullが許可されないため、望ましくない結果が生じる可能性があります。

テスト:

@Test
public void testToCollectionAlreadyCollection() {
    ArrayList<String> list = Lists.newArrayList(FIRST, MIDDLE, LAST);
    assertSame("no need to change, just cast", list, toCollection(list));
}

@Test
public void testIterableToCollection() {
    final ArrayList<String> expected = Lists.newArrayList(FIRST, null, MIDDLE, LAST);

    Collection<String> collection = toCollection(new Iterable<String>() {
        @Override
        public Iterator<String> iterator() {
            return expected.iterator();
        }
    });
    assertNotSame("a new list must have been created", expected, collection);
    assertTrue(expected + " != " + collection, CollectionUtils.isEqualCollection(expected, collection));
}

コレクションのすべてのサブタイプ(Set、Listなど)に同様のユーティリティを実装します。これらはすでにグアバの一部であると思いますが、私はそれを見つけていません。


1
あなたの1年前の回答は、新しい質問stackoverflow.com/questions/32570534/…の基礎であり、多くの意見やコメントを集めています。
Paul Boddington、

6

すぐに呼び出すようcontainscontainsAllequalshashCoderemoveretainAllsizeまたはtoArray、あなたはとにかく要素をトラバースする必要があると思います。

isEmptyまたはのようなメソッドを時々呼び出すだけの場合はclear、コレクションを遅延して作成した方がいいと思います。あなたは例えばバッキングを持つことができますArrayList以前に反復された要素を格納するためを。

私はどのライブラリでもそのようなクラスを知りませんが、書くのはかなり簡単な練習になるはずです。



6

Java 8では、これを実行してtoからすべての要素を追加IterableCollection、それを返すことができます。

public static <T> Collection<T> iterableToCollection(Iterable<T> iterable) {
  Collection<T> collection = new ArrayList<>();
  iterable.forEach(collection::add);
  return collection;
}

@Afreysの回答に触発されました。


5

RxJavaはハンマーであり、これはちょっと爪のように見えるので、

Observable.from(iterable).toList().toBlocking().single();

23
おそらくjqueryを関与させるいくつかの方法はありますか?
ドミトリー・ミンコフスキー

3
RxJavaにnullアイテムがあるとクラッシュします。じゃないですか
MBH

RxJava2はnull項目を許可しないと思います。RxJavaでは問題ないはずです。
DariusL 2017

4

これは、Java 8でこれを行うための優れた方法のSSCCEです

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class IterableToCollection {
    public interface CollectionFactory <T, U extends Collection<T>> {
        U createCollection();
    }

    public static <T, U extends Collection<T>> U collect(Iterable<T> iterable, CollectionFactory<T, U> factory) {
        U collection = factory.createCollection();
        iterable.forEach(collection::add);
        return collection;
    }

    public static void main(String[] args) {
        Iterable<Integer> iterable = IntStream.range(0, 5).boxed().collect(Collectors.toList());
        ArrayList<Integer> arrayList = collect(iterable, ArrayList::new);
        HashSet<Integer> hashSet = collect(iterable, HashSet::new);
        LinkedList<Integer> linkedList = collect(iterable, LinkedList::new);
    }
}

4

インターフェイスで宣言されているデフォルトではなくListProjectのを取得しようとしたときに、同様の状況に遭遇しました。したがって、(から拡張された)私のインターフェースでは、の代わりにを返すようにメソッドを宣言しました。Iterable<T> findAll()CrudRepositoryProjectRepositoryCrudRepositoryfindAll()List<Project>Iterable<Project>

package com.example.projectmanagement.dao;

import com.example.projectmanagement.entities.Project;
import org.springframework.data.repository.CrudRepository;
import java.util.List;

public interface ProjectRepository extends CrudRepository<Project, Long> {

    @Override
    List<Project> findAll();
}

これは、変換ロジックや外部ライブラリの使用を必要としない、最も単純なソリューションだと思います。


2

二つの発言

  1. Iterableをコレクションに変換してforeachループを使用する必要はありません。Iterableはそのようなループで直接使用できます。構文に違いはないため、元の質問がなぜ行われたのかまったくわかりません。
  2. IterableをCollectionに変換する推奨方法は安全ではありません(CollectionUtilsにも同じ)-next()メソッドの後続の呼び出しが異なるオブジェクトインスタンスを返す保証はありません。さらに、この懸念は純粋な理論ではありません。たとえば、Hadoop Reducerのreduceメソッドに値を渡すために使用されるIterable実装は、フィールド値が異なるだけで、常に同じ値のインスタンスを返します。したがって、上からmakeCollection(またはCollectionUtils.addAll(Iterator))を適用すると、すべて同じ要素を持つコレクションになります。


1

依存関係のない単純な1行のソリューションはありませんでした。簡単な使い方

List<Users> list;
Iterable<IterableUsers> users = getUsers();

// one line solution
list = StreamSupport.stream(users.spliterator(), true).collect(Collectors.toList());

0

Eclipseコレクションファクトリを使用できます。

Iterable<String> iterable = Arrays.asList("1", "2", "3");

MutableList<String> list = Lists.mutable.withAll(iterable);
MutableSet<String> set = Sets.mutable.withAll(iterable);
MutableSortedSet<String> sortedSet = SortedSets.mutable.withAll(iterable);
MutableBag<String> bag = Bags.mutable.withAll(iterable);
MutableSortedBag<String> sortedBag = SortedBags.mutable.withAll(iterable);

また、変換することができますIterableLazyIterableと変換方法または使用可能な他の利用可能なAPIのいずれかを使用します。

Iterable<String> iterable = Arrays.asList("1", "2", "3");
LazyIterable<String> lazy = LazyIterate.adapt(iterable);

MutableList<String> list = lazy.toList();
MutableSet<String> set = lazy.toSet();
MutableSortedSet<String> sortedSet = lazy.toSortedSet();
MutableBag<String> bag = lazy.toBag();
MutableSortedBag<String> sortedBag = lazy.toSortedBag();

上記のMutableタイプはすべて拡張されjava.util.Collectionます。

注:私はEclipseコレクションのコミッターです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.