2013-05-08 20 views
9

Iterableを使用してJavaでSet Implementation(HashSet)を初期化したいとします。しかし、HashSetのコンストラクタはIterablesを受け入れず、Collections型のオブジェクトだけを受け入れます。Iterableを使用してセットを初期化する

Iterableからいくつかのサブタイプのコレクションに変換する方法はありますか。

答えて

6

HashSetコンストラクタは、Iterableが提供するもの以上のものに依存しています。コレクションの先頭にあるsizeを最適に知りたい基礎となるHashMapを構築する。サイズがわからない真実で控えめなIterableがある場合は、多くの明白な方法のいずれかでそれを普通のCollectionに変えることでIterableを前もって実現する必要があります。

一方、すでにサイズがわかっているより豊富なオブジェクトがある場合は、Iterableをコレクションにラップするミニマリストのアダプタクラスを作成し、呼び出しを転送するだけでsizeを実装しますiterator

public class IterableCollection<T> implements Collection<T> 
{ 
    private final Iterable<T> iterable; 

    public IterableCollection(Iterable<T> it) { this.iterable = it; } 

    @Override public Iterator<T> iterator() { return iterable.iterator(); } 

    @Override public int size() { return ... custom code to determine size ... } 

    @Override .... all others ... { throw new UnsupportedOperationException(); } 
} 
+0

良い説明。私はあなたのポイントと直感を得ると思います。 – VaidAbhishek

2

それぞれを追加するだけです。

public static <T> Set<T> setFromIterable(Iterable<T> i) { 
    HashSet<T> set = new HashSet<T>(); 
    Iterator<T> it = i.iterator(); 
    while (it.hasNext()) { 
     set.add(it.next()); 
    } 
    return set; 
} 

Iterable<Integer> someIterable = ...; 
Set<Integer> someSet = setFromIterable(someIterable); 

それが存在しないため、あなたは、コンストラクタnew HashSet<Integer>(someIterator)を使用しないでください注意。静的メソッドを呼び出すだけです。

+3

私はあなたが「Iterable」と「Iterator」を混乱させると思います。 –

+0

はい、そうです。しかしiterator()は動作しません。私が持っているオブジェクトもIterator()を返しますが、コンストラクタには受け入れられません。 – VaidAbhishek

+0

カーク:そうです。ありがとう。 @Vaidは私の編集を見てください。 – wchargin

5

確かに、this答えで示されています。基本的には、反復可能を反復処理し、コレクションにその内容をコピーします。次のように

public static <T> List<T> copyIterable(Iterable<T> iterable) { 
    Iterator<T> iter = iterable.iterator(); 
    List<T> copy = new ArrayList<T>(); 
    while (iter.hasNext()) 
     copy.add(iter.next()); 
    return copy; 
} 

は、それを使用して、結果のListオブジェクトはHashSetコンストラクタにパラメータとして渡すことができます。

Iterable<Integer> list = Arrays.asList(1, 2, 3); 
List<Integer> copy = copyIterable(list); 
Set<Integer> aSet = new HashSet<Integer>(copy); 

EDIT

私はすべてに沿って誤解されてきました。 IterableCollectionのスーパーインターフェイスなので、IterableCollectionで始まっていればシンプルな(ただし安全ではない)キャストがトリックを行います。

Iterable<Integer> list = Arrays.asList(1, 2, 3); 
Set<Integer> aSet = new HashSet<Integer>((Collection)list); // it works! 
+0

Downovoter:コメントしますか? –

+0

Iterableを明示的に反復すること、またはIteratorを自分自身で消費することは避けていました。私は、それがHashSetのコンストラクタまたはSet Implementationに受け入れられるように、メカニズムを探しています。 (私はあなたに投票しませんでした)。しかし、私に回避策を教えてもらうと、私は間違いなくあなたを失望させるでしょう。 :-) – VaidAbhishek

+1

これはIterableではなくIteratorを受け入れます。 – wchargin

32

あなたはGuavaを使用することができます。

Set<T> set = Sets.newHashSet(iterable); 

か、それは文、静的インポートのように読めるようにする、

import static com.google.common.collect.Sets.*; 

Set<T> set = newHashSet(iterable); 
0

Iterableインターフェースは "foreachの" 構文が作業することができますので、クリーンな方法がありそうです:

public <T> Set<T> toSet(Iterable<T> collection) { 
    HashSet<T> set = new HashSet<T>(); 
    for (T item: collection) 
     set.add(item); 
    return set; 
} 
関連する問題