web-dev-qa-db-ja.com

Java配列を反復可能に変換

たとえば、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に割り当てられないのですか? も確認してください。

また、何らかのライブラリ(グアバなど)を使用する場合は、これがなぜベストなのかを説明してください。 (Googleからの完全な回答ではないため:P)

最後に、それについて宿題があるように見えるので、宿題のコードを投稿しないでください。

125
ntg
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();
103
fmucar

ちょうど私の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.");
            }
        };
    }
};
41

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();
27
Jin Kwon

Guavaは、必要なアダプターを Int.asList() として提供します。関連するクラスの各プリミティブ型に相当するものがあります(例:Booleansの場合はbooleanなど).

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.asListを使用するための上記の提案は、たとえIterator<int[]>ではなくIterator<Integer>を取得するためにコンパイルされても機能しません。何が起こるかというと、配列を基にしたリストを作成するのではなく、配列を含む1要素の配列リストを作成したということです。

20
BeeOnRope

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

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

イテレータ自体は怠__なUnmodifiableIteratorですが、それがまさに私が必要としたものです。

8
mindas

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

配列にプリミティブ型またはWrapper型を選択できる場合、このような状況にはWrapper型を使用しますが、もちろん、必ずしも便利または必須というわけではありません。できることは2つだけです。

1)各プリミティブデータ型配列の静的メソッドを使用してクラスを作成できます(boolean, byte, short, int, long, char, float, doubleIterable<WrapperType>を返します。これらのメソッドは、Iteratorの匿名クラスを使用します(Iterable以外)。メソッドを実装するためのフィールドとしての引数(たとえばint[])。

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

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

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

配列またはObjectを使用するメソッドの引数としてIterableを使用する3番目の戦略もあり、引数がどの型であるかを判別するために型チェックが必要になりますが、お勧めしませんオブジェクトが常に必要な型であるとは限らず、特定の場合には別個のコードが必要であると通常考慮する必要があるためです。

結論として、単純なArrays.asList(T...)を使用して多くのコードを節約する一般的な型としてプリミティブ型を使用できないのは、Javaの問題のある一般的な型システムの障害です。したがって、プリミティブ型の配列ごとにプログラムする必要があります。そのようなメソッド(基本的に、使用される型引数ごとに別個のメソッドを作成するC++プログラムで使用されるメモリに違いはありません)。

3
CodingVirus01

IterableOf from Cactoos を使用できます。

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"
);
3
yegor256

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

    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

1
Binod Pant