2013-01-23 111 views
15

我搜索了一段时间,一直在努力寻找这个,我试图生成几个随机的,唯一的数字是C#。我使用System.Random,和我使用的是datetime.now.ticks种子:生成随机,唯一的值C#

public Random a = new Random(DateTime.Now.Ticks.GetHashCode()); 
private void NewNumber() 
    { 
    MyNumber = a.Next(0, 10); 
    } 

我打电话NewNumber(定期),但问题是我经常收到重复的数字。有人建议,因为我每次做这件事都是随机的,它不会产生一个随机数,所以我把声明放在我的函数之外。任何建议或比使用System.Random更好的方法?谢谢

+2

http://csharpindepth.com/Articles/Chapter12/Random.aspx – Habib

+0

只要你只是创建Random对象一次,你不应该有问题。如果你想要的数字是唯一的(还没有这个数字),那么你需要添加额外的,而不仅仅是使用随机 – RoneRackal

+1

你在寻找“数字1..10排列”而不是“随机数在范围1..10“? (Definiitely给你随机序列10个唯一的数字) –

回答

14

我打电话NewNumber()定期,但问题是我经常得到 重复的数字。

Random.Next不保证数字是唯一的。你的范围是从0到10,你可能会得到重复的值。可能是你可以设置一个int的列表,并在检查它是否包含重复之后在列表中插入随机数。例如:

public Random a = new Random(); // replace from new Random(DateTime.Now.Ticks.GetHashCode()); 
           // Since similar code is done in default constructor internally 
public List<int> randomList = new List<int>(); 
int MyNumber = 0; 
private void NewNumber() 
{ 
    MyNumber = a.Next(0, 10); 
    if (!randomList.Contains(MyNumber)) 
     randomList.Add(MyNumber); 
} 
+2

+1。对于任何超过10个列表的选择都不好,HashSet会更好。并且不需要按照这种方式初始化随机数 - 在默认的构造函数中完成类似的代码... –

+0

感谢堆完美运行! –

13

如果范围仅为0到9,您可以尝试对可能的整数进行混洗。这增加了避免编号生成中的任何冲突的好处。

var nums = Enumerable.Range(0, 10).ToArray(); 
var rnd = new Random(); 

// Shuffle the array 
for (int i = 0;i < nums.Length;++i) 
{ 
    int randomIndex = rnd.Next(nums.Length); 
    int temp = nums[randomIndex]; 
    nums[randomIndex] = nums[i]; 
    nums[i] = temp; 
} 

// Now your array is randomized and you can simply print them in order 
for (int i = 0;i < nums.Length;++i) 
    Console.WriteLine(nums[i]); 
+0

我刚刚测试了一个,它运行得很好!非常感谢! –

+0

小心!这是一个不正确的洗牌实施!我会立即发布一个正确的实施。 –

+0

(现在编辑我的评论太晚了)。请在下面查看我的帖子以获取正确的实施,以及关于它的一些讨论的链接。 –

1

取决于你是什么真的是你可以做这样的事情后:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace SO14473321 
{ 
    class Program 
    { 
     static void Main() 
     { 
      UniqueRandom u = new UniqueRandom(Enumerable.Range(1,10)); 
      for (int i = 0; i < 10; i++) 
      { 
       Console.Write("{0} ",u.Next()); 
      } 
     } 
    } 

    class UniqueRandom 
    { 
     private readonly List<int> _currentList; 
     private readonly Random _random = new Random(); 

     public UniqueRandom(IEnumerable<int> seed) 
     { 
      _currentList = new List<int>(seed); 
     } 

     public int Next() 
     { 
      if (_currentList.Count == 0) 
      { 
       throw new ApplicationException("No more numbers"); 
      } 

      int i = _random.Next(_currentList.Count); 
      int result = _currentList[i]; 
      _currentList.RemoveAt(i); 
      return result; 
     } 
    } 
} 
8

我张贴正确执行洗牌的算法,因为另一张贴在这里不生产一个统一的洗牌。

正如其他答案所述,对于少量要随机化的值,您可以简单地使用这些值填充数组,然后使用数组,然后使用所需的许多值。

以下是Fisher-Yates Shuffle(又名Knuth Shuffle)的实现。 (阅读该链接的“实现错误”部分(搜索“总是从每次迭代中的整个有效数组索引中选择j”),以查看关于此处发布的其他实现的错误的一些讨论。)

using System; 
using System.Collections.Generic; 

namespace ConsoleApplication2 
{ 
    static class Program 
    { 
     static void Main(string[] args) 
     { 
      Shuffler shuffler = new Shuffler(); 
      List<int> list = new List<int>{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
      shuffler.Shuffle(list); 

      foreach (int value in list) 
      { 
       Console.WriteLine(value); 
      } 
     } 
    } 

    /// <summary>Used to shuffle collections.</summary> 

    public class Shuffler 
    { 
     /// <summary>Creates the shuffler with a <see cref="MersenneTwister"/> as the random number generator.</summary> 

     public Shuffler() 
     { 
      _rng = new Random(); 
     } 

     /// <summary>Shuffles the specified array.</summary> 
     /// <typeparam name="T">The type of the array elements.</typeparam> 
     /// <param name="array">The array to shuffle.</param> 

     public void Shuffle<T>(IList<T> array) 
     { 
      for (int n = array.Count; n > 1;) 
      { 
       int k = _rng.Next(n); 
       --n; 
       T temp = array[n]; 
       array[n] = array[k]; 
       array[k] = temp; 
      } 
     } 

     private System.Random _rng; 
    } 
} 
+0

@downvoters:你是否在调查其他随机洗牌问题?有问题的答案是接受答案之下的答案。它使用了不正确的随机播放算法。另请参阅我对该答案的评论。 –

+0

为什么这比另一个好? (apar从你说它通用) –

+0

@Mitulátbáti你的意思是“其他”的答案?如果你的意思是“接受的答案”,那么这一个更好,因为它具有复杂性'O(N)',而接受的答案具有复杂性'O(N^2)'。 –

-1

你也可以使用一个DataTable存储每个随机值,然后简单地执行而随机方法!=值在DataColumn的

8

注意,我不建议这样:)。 这里有一个 “oneliner” 以及:

//This code generates numbers between 1 - 100 and then takes 10 of them. 
var result = Enumerable.Range(1,101).OrderBy(g => Guid.NewGuid()).Take(10).ToArray(); 
+0

就像你去过的地方。但是为什么不呢:'Enumerable.Range(0,9).OrderBy(g => rand.NextDouble())。ToList()'然后你得到范围作为每个问题。 – SDK

+1

如果你想要两个唯一的数字在1和10,000,000之间,这将会非常缓慢。 – Rob

-3

试试这个:

private void NewNumber() 
    { 
    Random a = new Random(Guid.newGuid().GetHashCode()); 
    MyNumber = a.Next(0, 10); 
    } 

一些Explnations:

Guidbase on here:表示一个全局唯一标识符(GUID)

Guid.newGuid()产生一个唯一的标识符,如"936DA01F-9ABD-4d9d-80C7-02AF85C822A8"

,这将是唯一在全宇宙base on here

哈希码here从我们的唯一标识符生成一个唯一的整数

所以Guid.newGuid().GetHashCode()为我们提供了一个唯一的编号和随机类将产生真正的随机数扔这

+3

请添加说明。 – OhBeWise

+0

@Rob是的,这会产生一个独特的价值,你测试了吗? – AliTheOne

+3

不,它不会。没有任何理由,连续两次调用都不会产生相同的值。为每个样品重新播种是一种经典的反模式。 –

0

而在这里我的版本发现N随机唯一编号使用HashSet。 看起来很简单,因为HashSet只能包含不同的项目。 这很有趣 - 使用List或Shuffler会更快吗?

using System; 
using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
    class RnDHash 
    { 
     static void Main() 
     { 
      HashSet<int> rndIndexes = new HashSet<int>(); 
      Random rng = new Random(); 
      int maxNumber; 
      Console.Write("Please input Max number: "); 
      maxNumber = int.Parse(Console.ReadLine()); 
      int iter = 0; 
      while (rndIndexes.Count != maxNumber) 
      { 
       int index = rng.Next(maxNumber); 
       rndIndexes.Add(index); 
       iter++; 
      } 
      Console.WriteLine("Random numbers were found in {0} iterations: ", iter); 
      foreach (int num in rndIndexes) 
      { 
       Console.WriteLine(num); 
      } 
      Console.ReadKey(); 
     } 
    } 
} 
-2

您可以使用C#

Random ran = new Random(); 
int randomno = ran.Next(0,100); 

基本随机函数,你现在可以使用值在randomno你想要什么,但请记住,这将产生0100之间的随机数只有你可以扩展到任何数字。

+0

这没有给予独特价值的受让人。 –

0

请检查此准备好使用的方法:在范围内给出&您想获得的号码的数量。

public static int[] getUniqueRandomArray(int min, int max, int count) { 
    int[] result = new int[count]; 
    List<int> numbersInOrder = new List<int>(); 
    for (var x = min; x < max; x++) { 
     numbersInOrder.Add(x); 
    } 
    for (var x = 0; x < count; x++) { 
     var randomIndex = Random.Range(0, numbersInOrder.Count); 
     result[x] = numbersInOrder[randomIndex]; 
     numbersInOrder.RemoveAt(randomIndex); 
    } 

    return result; 
}