を印刷したい場合は、この質問はAPH-を壊すことがあり、ここで
Arrays.stream(persons).filter(x -> x!=0).distinct().limit(20).forEach(System.out::println);
//シャッフル最初の1時間に8件の回答を記録しています(1時間あたりの回答)。通常、これは悪い兆候ですが、驚くべきことに、私がこの複製をdelcareしたいという疑問を見つけませんでした。
残念ながら、ほとんどの「単純な」回答には実際には重大な欠点があります。最も重要なのは、提案されたソリューションが特定の設定に対して非効率的であること、またはTotal Correctnessを証明できないテクニックを採用することです。つまり、アルゴリズムの終了が証明されない可能性があります。これは、Set
に乱数を加えることに沸騰するアプローチを指し、別の要素の数を追跡するためにこのSet
を使用します。したがって、たとえば、このコード
Set<Integer> set = new HashSet<Integer>();
Random random = new Random(0);
while (set.size() < sampleSize) {
set.add(min + rand.nextInt(max));
}
にループはを終了したことがないかもしれません。あなたは、20個の異なる数字が選択されることを単に証明することはできません。 Random
インスタンスは、最初の呼び出しで0
を返します。 2回目の呼び出しで0
が返されることがあります。そして、「実際の」第3コール....もちろんyou can never be sure.
、で、通常ループは遅かれ早かれ、終了しますが、これはパラメータに依存します。選択するように要求された場合0と10の間の20の異なる乱数は、ではなく、となります。
int[] ints = new Random(0).ints(0, 10).distinct().limit(20).toArray();
このように、これらのパラメータは妥当性を確認するために慎重にチェックする必要があります。
しばしば様々な形で提案された他のオプションの中から選択する項目を予め充填されているリストにCollections#shuffle
を使用することです。これは、このリストが100または1000個の要素しか持たない場合に適用されます。しかし、100000000の要素を使ってリストを埋めることは、あまりにもメモリを消費しており、シャッフルこのリストはあまりにも時間がかかります。
一般的にこれを解決するための多彩な手法があります。それはReservoir Samplingと呼ばれます。
(そこリザーバーサンプリングの実装に関するいくつかの質問がありますが、この非常に一般的なタスクのためのソリューションとして提案されていないようでしたことに注意してください)
ここでは、Javaでの貯留サンプリングの実装です。 (この実装での不備や欠点がある場合は、私を落とし
/**
* Creates a collection with the given size, containing random values
* between the given minimum value (inclusive) and maximum value
* (exclusive). The resulting collection will contain the values
* in ascending order.
*
* @param size The size of the returned collection
* @param min The minimum value (inclusive)
* @param max The maximum value (exclusive)
* @param random The random number generator
* @return The collection
* @throws IllegalArgumentException If the requested size is larger than
* the difference between the maximum value and the minimum value
*/
public static Collection<Integer> randomSample(
int size, int min, int max, Random random)
{
if (size > max - min)
{
throw new IllegalArgumentException(
"Can not create a sample of size "+size+
" with values between "+min+" and "+max);
}
Set<Integer> set = new LinkedHashSet<Integer>(size);
int n = size;
for (int i = 0; i < max - min; i++)
{
double d = (double) size/((max - min) - i);
if (random.nextDouble() < d)
{
set.add(i + min);
n--;
}
if (n <= 0)
{
break;
}
}
return set;
}
:与えられたサンプルのサイズと範囲について、それが昇順で所望の範囲内(ランダム、ユニークな)整数のコレクションを返します。コメントの注釈)。
これは、同様のタスクのビルディングブロックとして使用できます。たとえば、あなたのケースでは、あなたが指標のランダムなサンプルを作成し、目的の要素選ぶためにこれを使用することもできます。他の例について
int persons[] = new int[1000];
int sample[] = new int[20];
Collection<Integer> indices = randomSample(20, 0, 1000);
int n = 0;
for (Integer index : indices)
{
sample[n] = index;
n++;
}
を、あなたが返されるインデックスからリストを作成することもできますし、このリストをシャッフルしてください。しかし、この場合、可能なすべての入力を含む(潜在的に大きい)リストではなく、(小さな)サンプルだけをシャッフルする必要があります。
Java 8を使用する場合、適切なランダムメソッドを使用して、希望のストリームを取得することができます – fge
繰り返しを避けるには、選択した後で配列から要素を削除します。 0を避けるには、それらを数えないでください(選択した後に配列からそれらを削除することもできます) – Aaron
人をリストに格納してからランダムなインデックスを20回取得し、その人をリストから削除します。あるいは、リスト全体で 'Collections.shuffle()'を実行した後、最初の20個のエントリを使用します。 – Robert