2012-05-12 283 views
1

我有一個建立的範圍,我想從該範圍內選擇一組隨機數(10%),同時確保它沒有重複值。避免重複值

如何以及在哪裏對我的程序進行編碼?

下面是摘錄。

// Number of Items  
int range = numberOfItems [itemNumber - 1]; 
// Determine 10 percent of the given range 
int tenPercentOfRange = (int)(range * 0.1); 
int number = 0; 
int[] numbers = new int[tenPercentOfRange]; 

int index = 0; 

for(;index < tenPercentOfRange;) 
{ 
    // Randomly select 10% of the items for a given item. 
    number = (int) (range * Math.random()) + 1; 
    if(!Arrays.asList(numbers).contains(number)) 
    { 
    numbers[index] = number; 
    index++; 
    // .................. 
+1

使用HashSet的,如果該號碼不在集合,使用它,否則再生? – DarthVader

+1

一個不相關的技巧:你可以使用ArrayList 而不是你現在正在用int數組做什麼。 – AHungerArtist

+0

@DarthVader沒有哈希集(與任何一般哈希相同)自動銷燬重複出現? – 2012-05-12 21:45:24

回答

2

最簡單的方法(雖然不是最有效的)將可能是填充列表的所有元素,使用Collections.shuffle(),然後選擇第一個10%的元素。

由於排列不會有兩次相同的進入(假設您使用這種方式填充它),所以前10%的元素也將是唯一的,因此它很適合。

0

如果您只需要整數範圍的10%,那麼重複您的方法直到您獲得一個不同的數字更有效。這使用LinkedHashSet高效檢查重複項。

final int range = 1000, sampleSize = range/10; 
final Set<Integer> rnds = new LinkedHashSet<Integer>(); 
final Random r = new Random(); 
for (int i = 0; i < sampleSize;) if (rnds.add(r.nextInt(range) + 1)) i++; 
System.out.println(rnds); 
final int[] result = new int[sampleSize]; 
int i = 0; 
for (int nr : rnds) result[i++] = nr; 
2

使用collection.shuffle(),並選擇指定大小的子列表,或者把你的價值觀在一個列表,並在指數

found.add (list.remove (random.nextInt (list.size())); 

爲X次刪除元素。在每一步中,列表的大小都會減小,並且沒有元素會出現兩次。

但是,對於非常大的範圍 - 可以說有效長期的範圍,建立一個列表來洗牌或從中挑選值是不合適的。

因此,創建一個Set,並選擇隨機值,將它們添加到列表中,直到set.size()等於您需要的大小。

Runnable的例子:

import java.util.*; 

public class Empty { 

    static Random random = new Random(); 

    public static void main (String args []) 
    { 
     show (pick (10, 100)); 
     show (securePick (10, 100000)); 
    } 

    static public List <Integer> pick (int n, int max) { 
     List <Integer> result = new ArrayList <Integer>(); 
     List <Integer> range = new ArrayList <Integer> (max); 
     for (int i= 0; i < max; ++i) 
      range.add (i); 
     for (int i= 0; i < n; ++i) 
      result.add (range.remove (random.nextInt (range.size()))); 
     return result; 
    } 

    static public Set <Integer> securePick (int n, int max) { 
     Set <Integer> result = new HashSet <Integer>(); 
     while (result.size() < n) 
      result.add (random.nextInt (max)); 
     return result; // <Integer> 
    } 

    public static void show (List <Integer> liste) 
    { 
     System.out.print ("["); 
     for (int i : liste) 
      System.out.print (i + ", "); 
     System.out.println ("\b\b]"); 
    } 

    public static void show (Set <Integer> liste) 
    { 
     System.out.print ("["); 
     for (int i : liste) 
      System.out.print (i + ", "); 
     System.out.println ("\b\b]"); 
    } 
} 
+0

我喜歡安全的選擇 – miks

+0

是的。 securePick唯一的問題是,如果你嘗試選擇999'999的1M值,但你自己有罪,而不是挑選相反; –

+1

是的,但在這種情況下,該方法的一個非常短的增強可以是如果n> max/2,則反過來,然後與反過去。 – miks