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


130

短いと甘い生成する方法があるList<Integer>、または多分 Integer[]またはint[]、いくつかの連続した値でstartの値end値は?

つまり、次のものよりも短いが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:Eclipseコレクション8.0を使用して、以下のドナルドの回答で提供されるコード。
  • guavaRange:以下のdavebの回答で与えられたコード。技術的には、これはaを作成するのList<Integer>ではなく、aを作成します。ただし、順序どおりにContiguousSet<Integer>実装さIterable<Integer>れるため、ほとんどの場合私の目的で機能します。
  • intStreamRange:以下のVladimirの回答に記載されているコードを使用IntStream.rangeClosed()します。これはJava 8で導入されました。
  • streamIterate:Java 8で導入された機能も使用する、以下のCatalinの回答に示されているコードIntStream

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

リスト作成スループット

...そしてサイズが10,000のリストの場合:

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

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

もちろん、ここで起こっているのは、guavaと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です:

リスト<整数>反復(長さ= 10)

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

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

多くの要素での長い反復により、多くのことを均等化しますが、日食とグアバは、10,000要素のテストでも2倍以上の速さを保ちます。

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


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


Apache Commonsの場合、stackoverflow.com
a / 5744861/560302

回答:


184

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

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

2
上記の回答のパフォーマンス結果をラベルintStreamRangeで追加しました
BeeOnRope

API 24+が必要
gcantoni

28

さて、このライナーは適格かもしれません(Guava Rangesを使用)

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

これは作成されませんList<Integer>が、ContiguousSet多くの同じ機能の提供は、特に実装するIterable<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]

7
asList()あなたが本当に必要でない限り私はそこでは使用しませんList... ...によってContiguousSet生成されたものasSetは軽量です(範囲とドメインが必要です)が、asList()実際にすべての要素をメモリに格納するリストを作成します(現在)。
ColinD 2012

1
同意した。OPはリストまたは配列を要求していましたが、それ以外の場合は
除外し

1
私は18.0を信じていRangeますが存在しますがRanges、彼らはこのasSet方法を廃止しました。私の古いバージョンでasSetは、は非推奨であり、削除されたようです。範囲は明らかに連続したコレクションにのみ使用されるものであり、私はこのソリューションが大好きですが、それを強制しています。
demongolem、2014年

APIには、次のようなコードが必要になりました。ContiguousSet.create(Range.closed(1、count)、DiscreteDomain.integers()
Ben

上記の回答のパフォーマンス結果をguavaRangeというラベルで追加しました
BeeOnRope

11

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

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

上記のこの回答のパフォーマンス結果をstreamIterateというラベルで追加しました。
BeeOnRope

1
明確化のポイントとして、制限引数は最後の数ではなく、リスト内の整数の数です。
neilireson 2018年

7

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をIntegerとしてボックス化IntListしたくないが、結果としてリスト構造が必要な場合は、IntIntervalfrom Eclipseコレクションで使用できます。

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

IntListメソッドを持ってsum()min()minIfEmpty()max()maxIfEmpty()average()およびmedian()インターフェイスで利用できます。

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

アンはIntervalあるList<Integer>が、それは怠惰と不変です。特にコレクションを扱う場合に、テストデータの生成に非常に役立ちます。必要であれば、あなたは簡単に間隔をコピーすることができListSetまたはBagとして、次のとおりです。

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

AnがIntIntervalあるImmutableIntList延びていますIntList。また、コンバーターメソッドもあります。

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

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

Eclipseコレクション9.0の更新

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


上記の回答のパフォーマンス結果をeclipseCollectionsというラベルで追加しました
BeeOnRope

きちんと。ボクシングを回避する追加のプリミティブバージョンを使用して回答を更新しました。
Donald Raab

6

これは、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;  
}

3
そのループをfor(int i = begin; i <= end; ret.add(i++));:)に変更することで、さらに数文字を削ることができます
vaughandroid

ret.add(i)パーツをforループのインクリメントに移動すると、これが「短く」なるかどうかはよくわかりません。私はそれをすべて1行で記述した場合、そのロジックにより短いと
思い

@BeeOnRopeはい、確かに最短ではありませんが、確かに2行短くなっています:)すでに述べたように、これはCore Javaで短縮できる最も近いものです。
adarshr 2012

上記の回答のパフォーマンス結果を、classicArrayListというラベルで追加しました
BeeOnRope

3

グアバ山脈を使用できます

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

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

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;
}

-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;  
}

AtomicIntegerの使用は、リソースに対して非常に重く、私のテストでは約10倍遅くなります。しかし、マルチスレッドに対しては安全です。終了<開始しない検証
CL-R

1
AtomicIntegerを使用しても、メソッド内では意味がありません。メソッド呼び出し内のすべての文は、メソッドを呼び出したスレッドによって順番に実行されるため、AtomicIntegerからは何も得られませんが、スローで煩わしいgetAndIncrement()呼び出しが発生します。
イゴールロドリゲス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.