2016-04-19 22 views
3

私は100の要素を含む配列を持っています。繰り返しなく、ゼロを持つ20個のランダムな要素を出力したいと思います。Javaランダム関数で繰り返しとゼロを避ける方法は?

1000個のうち20個のランダムな番号のセットを正常に印刷しましたが、繰り返しやゼロを印刷できません。 助けてください!ここで

はコードです: -

import java.util.Random; 


public class MyClass { 
    public static void main(String args[]) { 
     int[] persons = new int[1000]; 
     int[] person = new int[20]; 
     Random random = new Random(); 

     for (int i = 0; i < person.length; i++) 
     { 
      person[i] = random.nextInt(persons.length); 
      System.out.println(person[i]); 
     } 
    } 
} 
+0

Java 8を使用する場合、適切なランダムメソッドを使用して、希望のストリームを取得することができます – fge

+0

繰り返しを避けるには、選択した後で配列から要素を削除します。 0を避けるには、それらを数えないでください(選択した後に配列からそれらを削除することもできます) – Aaron

+0

人をリストに格納してからランダムなインデックスを20回取得し、その人をリストから削除します。あるいは、リスト全体で 'Collections.shuffle()'を実行した後、最初の20個のエントリを使用します。 – Robert

答えて

0

どうHashSetを使用してはどうですか?

import java.util.HashSet; 
import java.util.Random; 
import java.util.Set; 

public class NonRepeatRandom { 
    public static void main(String[] args){ 
     final int low = 1; 
     Set<Integer> set = new HashSet<Integer>(); 
     Random rand = new Random(); 

     while (set.size() < 20) { 
      set.add(rand.nextInt(1000) + low); // set bound between 1 and 1000 
     } 
     System.out.println(set); 
    } 
} 
0

乱数の繰り返しを持っていることを意図しています。 For security reasonsあなたが繰り返しをしていない場合、次の数字は簡単な数字で推測できます。

結論として、良い書かれたランダム関数は、生成された数が少なくても繰り返し数を返しています。

実際に、すでに選択されている要素をシャッフルする方法を探しています。 Collections.shuffle()トリックを行うことができます。

0
import java.util.Random; 


public class MyClass { 
    public static void main(String args[]) { 
     int[] persons = new int[1000]; 
     int[] person = new int[20]; 
     Random random = new Random(); 

     for (int i = 0; i < person.length; i++) 
     { 
      int number = random.nextInt(persons.length); 
      while(number == 0 || IntStream.of(person).anyMatch(x -> x == number)) 
       number = random.nextInt(persons.length); 
      person[i] = number; 
      System.out.println(person[i]); 
     } 
    } 
} 

ここで注意しておきたいのは、配列に繰り返し数が残っているか0であれば、無限ループに入る可能性があることです。

配列に作る

他の方法あなたがそれを介してランダムに実行する前に、唯一のユニークな要素が含まれています。 How to get unique items from an array?

[EDIT]

コードIntStream.of(person).anyMatch(x -> x == number)に関するいくつかの説明。ここでは、結果配列を取得し、それをフィルタリングするために述語を使用できるようにストリームします。 numberの値が配列personに前に出現しているかどうかを調べています。もしそうなら、その番号を使用したくないので、persons配列から別の乱数ゲッターを行うだけです。

+0

リストのようなものはありません ...まだとにかく – fge

+0

これを削除するのを忘れました、それはコードでは使用されませんでした – Draken

0

小規模なアイデア

リストをシャッフルして最初の20番目のアイテムを使用できます。繰り返しとゼロがないことを確認します。

あなたはN個の異なるランダムなインデックスを作成し、要素を選択するためにそれらを使用することができCollections.shuffle(yourList)

0

を使用することができます。

int[] indices = ThreadLocalRandom.current() 
    .ints(0, persons.length) 
    .distinct() 
    .limit(N) 
    .toArray(); 
0

//あなたの配列

int[] filteredPersons = Arrays.stream(persons).filter(x-> x!=0).distinct().limit(20).toArray(); 

//プリントはあなただけ

1

を印刷したい場合は、この質問は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++; 
} 

を、あなたが返されるインデックスからリストを作成することもできますし、このリストをシャッフルしてください。しかし、この場合、可能なすべての入力を含む(潜在的に大きい)リストではなく、(小さな)サンプルだけをシャッフルする必要があります。

関連する問題