web-dev-qa-db-ja.com

Javaで連続整数のリストまたは配列を生成するにはどうすればよいですか?

いくつかのstart値からend値までの連続した値で、List<Integer>、またはおそらくInteger[]またはint[]を生成するための短くて甘い方法はありますか?

つまり、より短いが、同等の何か1 以下:

void List<Integer> makeSequence(int begin, int end) {
  List<Integer> ret = new ArrayList<>(end - begin + 1);
  for (int i=begin; i<=end; i++) {
    ret.add(i);
  }
  return ret;  
}

グアバの使用は問題ありません。

更新:

パフォーマンス分析

この質問には、ネイティブJava 8とサードパーティライブラリの両方を使用したいくつかの良い回答があったので、すべてのソリューションのパフォーマンスをテストすると思いました。

最初のテストは、次のメソッドを使用して、10個の要素のリスト[1..10]の作成をテストするだけです。

  • classicArrayList:上記の質問のコード(および基本的にadarshrの回答と同じ)。
  • eclipseCollections:Eclipse Collections 8.0を使用した以下の Donald's answer のコード。
  • guavaRangedaveb's answer 以下のコード。技術的には、これはList<Integer>を作成するのではなく、ContiguousSet<Integer>を作成しますが、Iterable<Integer>を順番に実装するため、ほとんどの場合、目的に合わせて機能します。
  • intStreamRangeVladimir's answer で与えられたコード。これはJava 8で導入されたIntStream.rangeClosed()を使用します。
  • streamIterateCatalin's answer で指定されたコード。これはJavaで導入されたIntStream機能も使用します8。

サイズ10のリストを使用した上記のすべてについて、1秒あたりのキロオペレーション数の結果を示します(数値が大きいほど良い)。

List creation throughput

...サイズ10,000のリストの場合:

enter image description here

最後のチャートは正しいです。EclipseとGuava以外のソリューションは遅すぎて、単一のピクセルバーを取得することさえできません。高速ソリューションは、10,000〜20,000times他よりも高速です。

もちろん、ここで起こっているのは、グアバとEclipseのソリューションが実際に10,000個の要素リストを具体化しないことです。これらは、開始点と終点の単純な固定サイズのラッパーです。各要素は、反復中に必要に応じて作成されます。このテストでは実際に反復処理を行わないため、コストは延期されます。他のすべてのソリューションは、実際にはメモリ内の完全なリストを具体化し、作成のみのベンチマークで大きな代償を払います。

もう少し現実的なことをして、すべての整数を繰り返して合計します。したがって、IntStream.rangeClosedバリアントの場合、ベンチマークは次のようになります。

@Benchmark
public int intStreamRange() {
    List<Integer> ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());  

    int total = 0;
    for (int i : ret) {
        total += i;
    }
    return total;  
}

ここでは、非実体化ソリューションが依然として最速ですが、写真は大きく変わります。 length = 10は次のとおりです。

List<Integer> Iteration (length=10)

...および長さ= 10,000:

List<Integer> Iteration (length=10,000)

多くの要素の長い反復により、状況は大幅に改善されますが、Eclipseとguavaは、10,000要素のテストでも2倍以上の速度を維持します。

したがって、本当にList<Integer>が必要な場合、Eclipseコレクションが最良の選択のように見えますが、もちろん、よりネイティブな方法でストリームを使用する場合(たとえば、.boxed()を忘れて、原始領域の縮小を行う)、おそらくこれらすべてのバリアントよりも高速になります。


1 おそらく、end <beginの場合、またはサイズが実装またはJVMの制限を超える場合(たとえば、2^31-1より大きい配列の場合)のエラー処理を除きます。

95
BeeOnRope

Java 8を使用すると、非常に単純なので、別のメソッドも必要ありません。

List<Integer> range = IntStream.rangeClosed(start, end)
    .boxed().collect(Collectors.toList());
148

まあ、この1つのライナーが資格を得る可能性があります(使用 グアバ範囲

    ContiguousSet<Integer> integerList = ContiguousSet.create(Range.closedOpen(0, 10), DiscreteDomain.integers());
    System.out.println(integerList);

これはList<Integer>を作成しませんが、ContiguousSetはほとんど同じ機能を提供し、特にInteger<Integer>と同じ方法でforeach実装を許可するList<Integer>を実装します。

古いバージョン(Guava 14より前)では、これを使用できます。

    ImmutableList<Integer> integerList = Ranges.closedOpen(0, 10).asSet(DiscreteDomains.integers()).asList();
    System.out.println(integerList);

両方が生成します:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
26
daveb

次のワンライナーJava 8バージョンは[1、2、3、3 ... 10]を生成します。 iterateの最初の引数はシーケンスの最初のnrであり、limitの最初の引数は最後の数字です。

List<Integer> numbers = Stream.iterate(1, n -> n + 1)
                              .limit(10)
                              .collect(Collectors.toList());
8
Catalin Ciurea

これは、Core Javaを使用して得られる最短の時間です。

List<Integer> makeSequence(int begin, int end) {
  List<Integer> ret = new ArrayList(end - begin + 1);

  for(int i = begin; i <= end; i++, ret.add(i));

  return ret;  
}
6
adarshr

Interval クラスを Eclipse Collections から使用できます。

List<Integer> range = Interval.oneTo(10);
range.forEach(System.out::print);  // prints 12345678910

Intervalクラスは遅延しているため、すべての値を格納するわけではありません。

LazyIterable<Integer> range = Interval.oneTo(10);
System.out.println(range.makeString(",")); // prints 1,2,3,4,5,6,7,8,9,10

メソッドは次のように実装できます。

public List<Integer> makeSequence(int begin, int end) {
    return Interval.fromTo(begin, end);
}

Intを整数としてボックス化することを避けたいが、結果としてリスト構造が必要な場合は、Eclipse Collectionsの IntListIntInterval とともに使用できます。

public IntList makeSequence(int begin, int end) {
    return IntInterval.fromTo(begin, end);
}

IntListには、インターフェイスで使用可能なメソッドsum()min()minIfEmpty()max()maxIfEmpty()average()、およびmedian()があります。

わかりやすくするために更新:2017/11/27

IntervalList<Integer>ですが、レイジーで不変です。特にコレクションを大量に処理する場合は、テストデータの生成に非常に役立ちます。必要に応じて、次のように間隔をListSet、またはBagに簡単にコピーできます。

Interval integers = Interval.oneTo(10);
Set<Integer> set = integers.toSet();
List<Integer> list = integers.toList();
Bag<Integer> bag = integers.toBag();

IntIntervalは、ImmutableIntListを拡張するIntListです。コンバーターメソッドもあります。

IntInterval ints = IntInterval.oneTo(10);
IntSet set = ints.toSet();
IntList list = ints.toList();
IntBag bag = ints.toBag();

IntervalIntIntervalには、同じequalsコントラクトがありません。

Eclipse Collections 9.の更新

プリミティブストリームからプリミティブコレクションを作成できるようになりました。好みに応じてwithAllおよびofAllメソッドがあります。好奇心が強い人は、なぜ here の両方があるのか​​を説明する。これらのメソッドは、可変および不変のInt/Long/Doubleリスト、セット、バッグ、スタック用に存在します。

Assert.assertEquals(
        IntInterval.oneTo(10),
        IntLists.mutable.withAll(IntStream.rangeClosed(1, 10)));

Assert.assertEquals(
        IntInterval.oneTo(10),
        IntLists.immutable.withAll(IntStream.rangeClosed(1, 10)));

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

5
Donald Raab

Guava Ranges を使用できます

を使用してSortedSetを取得できます

ImmutableSortedSet<Integer> set = Ranges.open(1, 5).asSet(DiscreteDomains.integers());
// set contains [2, 3, 4]
2
jmruc

これは私が見つけることができる最短です。

リストバージョン

public List<Integer> makeSequence(int begin, int end)
{
    List<Integer> ret = new ArrayList<Integer>(++end - begin);

    for (; begin < end; )
        ret.add(begin++);

    return ret;
}

配列バージョン

public int[] makeSequence(int begin, int end)
{
    if(end < begin)
        return null;

    int[] ret = new int[++end - begin];
    for (int i=0; begin < end; )
        ret[i++] = begin++;
    return ret;
}
0
Code Behind