2012-05-12 212 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