159

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

つまり、次の1より短いが、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とサードパーティライブラリの両方を使用していくつかの良い回答を受け取ったので、すべてのソリューションのパフォーマンスをテストすると思いました。

[1..10]最初のテストは、次の方法を使用して10個の要素のリストを作成することをテストするだけです。

  • classicArrayList:上記の私の質問のコード(そして本質的にadarshrの答えと同じ)。
  • eclipseCollections: EclipseCollections8.0を使用した以下のDonaldの回答に示されているコード。
  • guavaRange:以下のdavebの回答に示されているコード。技術的には、これは作成されませんList<Integer>が、むしろContiguousSet<Integer>-を作成しますが、順番に実装さIterable<Integer>れるため、ほとんどの場合、私の目的で機能します。
  • intStreamRange:以下のVladimirの回答IntStream.rangeClosed()に示されているコードで、Java8で導入された-を使用しています。
  • streamIterate :以下のCatalinの回答に示されているコードで、 Java8IntStreamで導入された機能も使用しています。

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

リスト作成スループット

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

ここに画像の説明を入力してください

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

もちろん、ここで起こっていることは、グアバとエクリプスのソリューションは実際にはいかなる種類の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;  
}

ここでは、非実体化ソリューションが依然として最速ですが、画像は大きく変化します。これが長さ=10です:

List <Integer>反復(長さ= 10)

...そして長さ=10,000:

List <Integer>反復(長さ= 10,000)

多くの要素にわたる長い反復は、物事を大幅に均等化しますが、日食とグアバは、10,000要素のテストでも2倍以上の速度を維持します。

したがって、本当に必要な場合はList<Integer>、eclipseコレクションが最良の選択のように思われますが、もちろん、よりネイティブな方法でストリームを使用する場合(たとえば、.boxed()プリミティブドメインを忘れて削減する場合)、これらすべてよりも速くなる可能性があります。バリアント。


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

4

9 に答える 9

246

Java 8では非常にシンプルなので、別のメソッドも必要ありません。

List<Integer> range = IntStream.rangeClosed(start, end)
    .boxed().collect(Collectors.toList());
于 2014-04-03T06:00:08.097 に答える
30

さて、このワンライナーは適格かもしれません(グアバレンジを使用)

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

これはを作成しませんList<Integer>ContiguousSet、ほとんど同じ機能を提供します。特に、と同じ方法で実装Iterable<Integer>できる実装を提供します。foreachList<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]
于 2012-04-20T08:07:54.907 に答える
16

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

List<Integer> numbers = Stream.iterate(1, n -> n + 1)
                              .limit(10)
                              .collect(Collectors.toList());
于 2016-03-20T14:04:12.273 に答える
9

EclipseコレクションIntervalのクラスを使用できます。

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を避けたいが、結果としてリスト構造が必要な場合IntListIntInterval、Eclipseコレクションからで使用できます。

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

IntListメソッド、、、、、があり、インターフェイスsum()で使用min()できます。minIfEmpty()max()maxIfEmpty()average()median()

明確にするための更新:2017年11月27日

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

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

AnIntIntervalImmutableIntList拡張するanですIntList。コンバーターメソッドもあります。

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

Intervalは同じ契約を結んでIntIntervalいません。equals

Eclipseコレクション9.0の更新

これで、プリミティブストリームからプリミティブコレクションを作成できます。好みに応じて方法がありwithAllます。興味があれば、ここofAllに両方がある理由を説明します。これらのメソッドは、可変および不変の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コレクションのコミッターです

于 2016-04-01T07:09:19.877 に答える
6

これは、CoreJavaを使用して取得できる最短の時間です。

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;  
}
于 2012-04-20T08:07:38.650 に答える
4

あなたはグアバの範囲を使用することができます

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

ImmutableSortedSet<Integer> set = Ranges.open(1, 5).asSet(DiscreteDomains.integers());
// set contains [2, 3, 4]
于 2012-04-20T08:09:36.377 に答える
1
int[] arr = IntStream.rangeClosed(2, 5).toArray();
System.out.println(Arrays.toString(arr));
// [2, 3, 4, 5]

Integer[] boxedArr = IntStream.rangeClosed(2, 5)
  .boxed().toArray(Integer[]::new);
System.out.println(Arrays.toString(boxedArr));

// Since Java 16
List<Integer> list1 = IntStream.rangeClosed(2, 5)
  .boxed().toList();
System.out.println(list1);

List<Integer> list2 = IntStream.rangeClosed(2, 5)
  .boxed().collect(Collectors.toList());
System.out.println(list2);

List<Integer> list3 = Arrays.asList(boxedArr);
System.out.println(list3);

List<Integer> list4 = new ArrayList<>();
IntStream.rangeClosed(2, 5).forEachOrdered(list4::add);
System.out.println(list4);
于 2021-03-15T07:28:06.323 に答える
0

これは私が見つけた最短のものです。

リストバージョン

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;
}
于 2012-04-20T08:28:24.090 に答える
-2

これはあなたのために働くかもしれません....

void List<Integer> makeSequence(int begin, int end) {

  AtomicInteger ai=new AtomicInteger(begin);
  List<Integer> ret = new ArrayList(end-begin+1);

  while ( end-->begin) {

    ret.add(ai.getAndIncrement());

  }
  return ret;  
}
于 2012-04-20T08:29:26.977 に答える