Java配列を反復可能に変換


150

たとえば、int、int [] fooなどのプリミティブの配列があります。小さいものかもしれません。

int foo[] = {1,2,3,4,5,6,7,8,9,0};

それからを作成する最良の方法は何Iterable<Integer>ですか?

Iterable<Integer> fooBar = convert(foo);

ノート:

ループを使用して応答しないでください(コンパイラーがループについてスマートに実行する方法について適切な説明ができない場合)。

また注意してください

int a[] = {1,2,3};
List<Integer> l = Arrays.asList(a);

コンパイルさえしません

Type mismatch: cannot convert from List<int[]> to List<Integer>

また 、配列がIterableに割り当てられないのはなぜですか? 答える前に。

また、いくつかのライブラリ(Guavaなど)を使用している場合は、これが最高の理由を説明してください。(Googleからの完全な回答ではないため:P)

最後に、宿題があるようですので、宿題のコードを投稿しないでください。



それらをLinkedListに追加し、そのセットのイテレータを返すだけです。

回答:


117
Integer foo[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

List<Integer> list = Arrays.asList(foo);
// or
Iterable<Integer> iterable = Arrays.asList(foo);

Integerただしint、これを機能させるには、配列ではなく配列を使用する必要があります。

プリミティブの場合、グアバを使用できます。

Iterable<Integer> fooBar = Ints.asList(foo);
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>15.0</version>
    <type>jar</type>
</dependency>

Java8の場合:(Jin Kwonの回答から)

final int[] arr = {1, 2, 3};
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();

10
2つの注記:1)intInteger2)ではなくを持ってListいるIterableので、3行目は無意味です。
maksimov 2012

1
彼には、なぜ3行目があるかというIterableが必要です。
fmucar 2012

5
2行目と3行目は私が言うオプションです:)
fmucar '26

1
これは宿題の一部ではなく、配列またはリストの内容を処理するデバッグ関数のコードを重複させないようにしようとしていました... Eclipseはそれが私が望むことをしないと思っているようです(たとえば、それはArrays.asList(foo)の結果をList <int []>として推論し、List <Integer>ではないと推論します...)質問...(
制限の

1
一般に、それを行う方法はたくさん考えられますが、私は何が最善であるか疑問に思っていました(たとえば、ループは私よりも遅くなると思います... {まあ、問題は私が何も考えられないことです!: )})また、stackoverflow.com / questions / 1160081 /…を確認してください。理由は何ですか、私の質問はなぜではなく、どのように、どのタイプのコンテナーが最適なのかです(なぜArrayListなのですか?実際、いくつかのAbstractListを想像できます) Genericsを使用するラッパー..、おそらくサイズに依存します...)
ntg

44

ちょうど私の2セント:

final int a[] = {1,2,3};

java.lang.Iterable<Integer> aIterable=new Iterable<Integer>() {

    public Iterator<Integer> iterator() {
       return new Iterator<Integer>() {
            private int pos=0;

            public boolean hasNext() {
               return a.length>pos;
            }

            public Integer next() {
               return a[pos++];
            }

            public void remove() {
                throw new UnsupportedOperationException("Cannot remove an element of an array.");
            }
        };
    }
};

9
remove()は、UnsupportedOperationExceptionをスローするデフォルトのメソッドであるため、Java 8では必要ありません。より良い説明メッセージを提供したい場合のみ。
Alex

+1 Iterator<Character>からを作成するのと同じようなことをしますString。あなた自身を実装するIterator(グアバの経由プリミティブ型にオブジェクト型から変換するために、すべての値を反復不避けるための唯一の方法のように思えるInts.asList()だけで得ることができるようにするために、例えば)IteratorからList作成されました。
spaaarky21 2017

2
あなたは正しいアレックスです。デフォルトのメソッドがJava 8に追加されました。2013年に、私はこの古いコードをここに追加しました。
Joerg Ruethschilling 2017年

29

Java 8では、これを行うことができます。

final int[] arr = {1, 2, 3};
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();

20

Guavaは、必要なアダプタをInt.asList()として提供します。関連するクラスの各プリミティブ型の等価であり、例えば、Booleansbooleanなど

int foo[] = {1,2,3,4,5,6,7,8,9,0};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
    System.out.println(i);
}

上記でArrays.asListIterator<int[]>なくを取得するためにコンパイルしても、上記の使用方法は機能しませんIterator<Integer>。発生するのは、配列に基づくリストを作成するのではなく、配列を含む配列の1要素のリストを作成したということです。


注:リンクは機能していません。Githubのリンク:github.com/google/guava/blob/master/guava/src/com/google/common/...
Orangle

ありがとう@Passi、修正済み(javadocにリンクするためにGoogleがサポートする方法が見つからないようです。提供したソースにリンクしました)。
BeeOnRope

8

私は同じ問題を抱えており、次のようにそれを解決しました:

final YourType[] yourArray = ...;
return new Iterable<YourType>() {
  public Iterator<YourType> iterator() {
     return Iterators.forArray(yourArray);   // Iterators is a Google guava utility
  }
}

イテレータ自体は怠惰ですUnmodifiableIteratorが、まさにそれが必要でした。


7

Java 8以降でIterableは、機能インターフェースがを返しますIterator。だからあなたはこれを行うことができます。

int[] array = {1, 2, 3};
Iterable<Integer> iterable = () -> Arrays.stream(array).iterator();
for (int i : iterable)
    System.out.println(i);

->

1
2
3

3

まず第一に、それがArrays.asList(T...)Wrapper型または非プリミティブデータ型を持つ配列の明らかに最良のソリューションであることに同意することしかできません。このメソッドはAbstractListArraysクラス内の単純なプライベート静的実装のコンストラクターを呼び出します。これは基本的に、指定された配列参照をフィールドとして保存し、必要なメソッドをオーバーライドしてリストをシミュレートします。

配列のプリミティブ型またはラッパー型のどちらかを選択できる場合、私はそのような状況でラッパー型を使用しますが、もちろん、それは必ずしも有用または必須ではありません。2つだけの可能性があるだろうあなたが行うことができます:

1)あなたは、各プリミティブデータ型の配列のための静的メソッドを持つクラスを作成することができます(boolean, byte, short, int, long, char, float, double返却Iterable<WrapperTypeを>これらの方法は、以下の匿名クラスを使用します。Iteratorほかに(Iterableint[]メソッドを実装するために、フィールドを構成するメソッドの引数(たとえば)の参照を含めることができます。

->このアプローチはパフォーマンスが高く、メモリを節約します(ただし、新しく作成されたメソッドのメモリを除いて、使用Arrays.asList()すると同じ方法でメモリが消費されます)

2)配列にはメソッドがないため(側で読み取られるため)あなたがリンクした)彼らはまた、Iteratorインスタンスを提供することはできません。本当に怠惰で新しいクラスを作成できない場合は、実装する既存のクラスのインスタンスを使用する必要があります。Iterableこれはインスタンス化以外に方法がないためですIterableまたはサブタイプ。
実装する既存のコレクション派生物を作成する唯一の方法Iterableループを使用する(上記の匿名クラスを使用する場合を除く)かIterable、プリミティブ型配列を許可するコンストラクター(Object[]プリミティブ型要素を持つ配列を許可しないため)を実装するクラスをインスタンス化しますが、私の知る限り、Java APIそのようなクラスはありません。

ループの理由は簡単に説明でき
ます。コレクションごとにオブジェクトが必要です。プリミティブデータ型はオブジェクトではありません。オブジェクトはプリミティブ型よりもはるかに大きいため、プリミティブ型配列の各要素に対して生成する必要がある追加のデータが必要です。つまり、3つの方法のうち2つ(Arrays.asList(T...)既存のコレクションを使用または使用)でオブジェクトの集約が必要な場合は、オブジェクトのプリミティブ値ごとに作成する必要があります。int[]ます。ラッパーオブジェクトを配列します。3番目の方法では、配列をそのまま使用し、匿名クラスで使用します。これは、高速なパフォーマンスのために好ましいと思います。

を使用する3番目の戦略もあり、引数の型を判別するには型チェックが必要になりますが、オブジェクトが常に必要な型であるとは限らないことを考慮する必要があるため、私はそれをまったくお勧めしません。場合によっては、別のコードが必要です。Object。as引数配列を使用するメソッドまたはIterable

結論として、プリミティブ型をジェネリック型として使用できないのは、Javaの問題のあるジェネリック型システムのせいですArrays.asList(T...)。そのため、プリミティブ型の配列ごとにプログラムする必要があります。そのようなメソッドが必要です(基本的に、C ++プログラムが使用するメモリと、使用する型の引数ごとに別個のメソッドを作成しますが、違いはありません)。


3

CactoosIterableOfから使用できます。

Iterable<String> names = new IterableOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);

次に、次のコマンドを使用してリストに変換できますListOf

List<String> names = new ListOf<>(
  new IterableOf<>(
    "Scott Fitzgerald", "Fyodor Dostoyevsky"
  )
);

または単にこれ:

List<String> names = new ListOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);

1

同様の回答がすでに投稿されていますが、新しいPrimitiveIterator.OfIntを使用する理由は明確ではないと思います。Java 8 PrimitiveIteratorはプリミティブなint型に特化しているため、適切な解決策はJava 8 PrimitiveIteratorを使用することです(そして、余分なボックス化/ボックス化解除のペナルティを回避します)。

    int[] arr = {1,2,3};
    // If you use Iterator<Integer> here as type then you can't get the actual benefit of being able to use nextInt() later
    PrimitiveIterator.OfInt iterator = Arrays.stream(arr).iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.nextInt());
        // Use nextInt() instead of next() here to avoid extra boxing penalty
    }

参照:https : //doc.bccnsoft.com/docs/jdk8u12-docs/api/java/util/PrimitiveIterator.OfInt.html


-2

java8では、IntSteamストリームをボックス化して整数のストリームにすることができます。

public static Iterable<Integer> toIterable(int[] ints) {
    return IntStream.of(ints).boxed().collect(Collectors.toList());
}

配列のサイズに基づいてパフォーマンスが重要になると思います。

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