C# 使用.NET随机化数组的最佳方法

C# 使用.NET随机化数组的最佳方法,c#,.net,algorithm,sorting,random,C#,.net,Algorithm,Sorting,Random,使用.NET随机化字符串数组的最佳方法是什么?我的数组包含大约500个字符串,我想用相同的字符串创建一个新的数组,但顺序是随机的 请在答案中包含一个C#示例。生成一个相同长度的随机浮点或整数数组。对该阵列排序,并在目标阵列上执行相应的交换 这将产生一个真正独立的排序。随机化数组是一项密集的工作,因为您必须在一组字符串之间移动。为什么不从数组中随机读取呢?在最坏的情况下,您甚至可以使用getNextString()创建包装器类。如果您确实需要创建一个随机数组,那么您可以执行以下操作 for i =

使用.NET随机化字符串数组的最佳方法是什么?我的数组包含大约500个字符串,我想用相同的字符串创建一个新的
数组
,但顺序是随机的


请在答案中包含一个C#示例。

生成一个相同长度的随机浮点或整数数组。对该阵列排序,并在目标阵列上执行相应的交换


这将产生一个真正独立的排序。

随机化数组是一项密集的工作,因为您必须在一组字符串之间移动。为什么不从数组中随机读取呢?在最坏的情况下,您甚至可以使用getNextString()创建包装器类。如果您确实需要创建一个随机数组,那么您可以执行以下操作

for i = 0 -> i= array.length * 5
   swap two strings in random places

*5是任意的

该算法简单但效率不高,O(N2)。所有的“orderby”算法通常都是O(N logn)。在数十万个元素下面,它可能不会有什么不同,但对于大型列表来说会有不同

var stringlist = ... // add your values to stringlist

var r = new Random();

var res = new List<string>(stringlist.Count);

while (stringlist.Count >0)
{
   var i = r.Next(stringlist.Count);
   res.Add(stringlist[i]);
   stringlist.RemoveAt(i);
}
var stringlist=…//将您的值添加到stringlist
var r=新的随机变量();
var res=新列表(stringlist.Count);
而(stringlist.Count>0)
{
var i=r.Next(stringlist.Count);
res.Add(stringlist[i]);
stringlist.RemoveAt(i);
}

O(N2)的原因很微妙:是O(N)操作,除非您从末尾按顺序删除。

如果您在.NET 3.5上,您可以使用以下IEnumerable coolness:

Random rnd=new Random();
string[] MyRandomArray = MyArray.OrderBy(x => rnd.Next()).ToArray();    
编辑:下面是相应的VB.NET代码:

Dim rnd As New System.Random
Dim MyRandomArray = MyArray.OrderBy(Function() rnd.Next()).ToArray()
第二次编辑,回应System.Random由于返回基于时间的序列而“不线程安全”和“仅适用于玩具应用程序”的评论:在我的示例中,Random()是完全线程安全的,除非您允许重新输入随机数组的例程,在这种情况下,您需要类似于
锁的东西(MyRandomArray)
为了不损坏您的数据,这将保护
rnd

另外,应该很好地理解System.Random作为熵的来源不是很强。如中所述,如果您正在做任何与安全相关的事情,您应该使用源自System.Security.Cryptography.RandomNumberGenerator的内容。例如:

using System.Security.Cryptography;


只要想一想,你就可以做到:

public string[] Randomize(string[] input)
{
  List<string> inputList = input.ToList();
  string[] output = new string[input.Length];
  Random randomizer = new Random();
  int i = 0;

  while (inputList.Count > 0)
  {
    int index = r.Next(inputList.Count);
    output[i++] = inputList[index];
    inputList.RemoveAt(index);
  }

  return (output);
}
public string[]随机化(string[]输入)
{
List inputList=input.ToList();
string[]输出=新字符串[input.Length];
随机随机发生器=新随机();
int i=0;
而(inputList.Count>0)
{
int index=r.Next(inputList.Count);
输出[i++]=输入列表[索引];
inputList.RemoveAt(索引);
}
返回(输出);
}
Random r=new Random();
列表=新列表(原始阵列);
List randomStrings=新列表();
而(list.Count>0)
{
int i=r.Random(list.Count);
添加(列表[i]);
列表。删除(i);
}

您正在寻找一种洗牌算法,对吗

好的,有两种方法可以做到这一点:聪明的人,但人们似乎总是误解它,把它弄错了,所以也许它并没有那么聪明,和愚蠢的石头,但谁在乎,因为它的工作方式

哑道
  • 创建第一个数组的副本,但应使用随机数标记每个字符串
  • 根据随机数对重复数组进行排序
此算法运行良好,但请确保您的随机数生成器不太可能标记具有相同数字的两个字符串。由于所谓的错误,这种情况的发生频率比您预期的要高。其时间复杂度为O(n log n)

妙法 我将把它描述为一个递归算法:

要洗牌大小为n的数组(索引范围为[0..n-1]):

如果n=0
  • 无所事事
如果n>0
  • (递归步骤)洗牌数组的前n-1个元素
  • 选择范围为[0..n-1]的随机索引x
  • 将索引n-1处的元素与索引x处的元素交换
迭代等价物是遍历一个迭代器,在执行过程中与随机元素交换,但请注意,不能在迭代器指向的元素之后与该元素交换。这是一个非常常见的错误,并导致有偏的无序移动


时间复杂度为O(n)。

以下是使用OLINQ的简单方法:

// Input array
List<String> lst = new List<string>();
for (int i = 0; i < 500; i += 1) lst.Add(i.ToString());

// Output array
List<String> lstRandom = new List<string>();

// Randomize
Random rnd = new Random();
lstRandom.AddRange(from s in lst orderby rnd.Next(100) select s);
//输入数组
List lst=新列表();
对于(inti=0;i<500;i+=1)lst.Add(i.ToString());
//输出阵列
List lstRandom=新列表();
//随机化
随机rnd=新随机();
lstRandom.AddRange(从RST orderby rnd中的s开始。下一步(100)选择s);

下面的实现使用了AKA-Knuth-Shuffle。它在O(n)时间内运行,并在适当的位置执行洗牌,因此比“按随机排序”技术性能更好,尽管它的代码行数更多。请参阅以获取一些比较性能度量。我使用了System.random,这对于非加密目的来说是很好的*

static class RandomExtensions
{
    public static void Shuffle<T> (this Random rng, T[] array)
    {
        int n = array.Length;
        while (n > 1) 
        {
            int k = rng.Next(n--);
            T temp = array[n];
            array[n] = array[k];
            array[k] = temp;
        }
    }
}

*对于较长的阵列,为了使(非常大的)置换数具有相同的可能性,有必要运行伪随机数生成器(PRNG)每次交换都要经过多次迭代以产生足够的熵。对于500个元素的数组,使用PRNG只能获得可能的500!置换中的一小部分。然而,Fisher-Yates算法是无偏的,因此洗牌将与您使用的RNG一样好。

Jacco,您的解决方案是自定义的IComparer不安全。排序例程要求比较器符合多个要求才能正常运行。其中第一个要求是一致性。如果对同一对对象调用比较器,它必须始终返回相同的结果。(比较也必须是可传递的)

未能满足这些要求可能会导致排序例程中出现许多问题,包括无限循环的可能性

关于关联的解决方案
Random r = new Random();
List<string> list = new List(originalArray);
List<string> randomStrings = new List();

while(list.Count > 0)
{
int i = r.Random(list.Count);
randomStrings.Add(list[i]);
list.RemoveAt(i);
}
// Input array
List<String> lst = new List<string>();
for (int i = 0; i < 500; i += 1) lst.Add(i.ToString());

// Output array
List<String> lstRandom = new List<string>();

// Randomize
Random rnd = new Random();
lstRandom.AddRange(from s in lst orderby rnd.Next(100) select s);
static class RandomExtensions
{
    public static void Shuffle<T> (this Random rng, T[] array)
    {
        int n = array.Length;
        while (n > 1) 
        {
            int k = rng.Next(n--);
            T temp = array[n];
            array[n] = array[k];
            array[k] = temp;
        }
    }
}
var array = new int[] {1, 2, 3, 4};
var rng = new Random();
rng.Shuffle(array);
rng.Shuffle(array); // different order from first call to Shuffle
   namespace System
    {
        public static class MSSystemExtenstions
        {
            private static Random rng = new Random();
            public static void Shuffle<T>(this T[] array)
            {
                rng = new Random();
                int n = array.Length;
                while (n > 1)
                {
                    int k = rng.Next(n);
                    n--;
                    T temp = array[n];
                    array[n] = array[k];
                    array[k] = temp;
                }
            }
        }
    }
        string[] names = new string[] {
                "Aaron Moline1", 
                "Aaron Moline2", 
                "Aaron Moline3", 
                "Aaron Moline4", 
                "Aaron Moline5", 
                "Aaron Moline6", 
                "Aaron Moline7", 
                "Aaron Moline8", 
                "Aaron Moline9", 
            };
        names.Shuffle<string>();
private ArrayList ShuffleArrayList(ArrayList source)
{
    ArrayList sortedList = new ArrayList();
    Random generator = new Random();

    while (source.Count > 0)
    {
        int position = generator.Next(source.Count);
        sortedList.Add(source[position]);
        source.RemoveAt(position);
    }  
    return sortedList;
}
public static class EnumerableExtensions
{
    static readonly RNGCryptoServiceProvider RngCryptoServiceProvider = new RNGCryptoServiceProvider();
    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> enumerable)
    {
        var randomIntegerBuffer = new byte[4];
        Func<int> rand = () =>
                             {
                                 RngCryptoServiceProvider.GetBytes(randomIntegerBuffer);
                                 return BitConverter.ToInt32(randomIntegerBuffer, 0);
                             };
        return from item in enumerable
               let rec = new {item, rnd = rand()}
               orderby rec.rnd
               select rec.item;
    }
}
Enumerable.Range(0,1000).Shuffle().ToList()
Random random = new Random();
array.ToList().Sort((x, y) => random.Next(-1, 1)).ToArray();
class Program
{
    static string[] words1 = new string[] { "brown", "jumped", "the", "fox", "quick" };

    static void Main()
    {
        var result = Shuffle(words1);
        foreach (var i in result)
        {
            Console.Write(i + " ");
        }
        Console.ReadKey();
    }

   static string[] Shuffle(string[] wordArray) {
        Random random = new Random();
        for (int i = wordArray.Length - 1; i > 0; i--)
        {
            int swapIndex = random.Next(i + 1);
            string temp = wordArray[i];
            wordArray[i] = wordArray[swapIndex];
            wordArray[swapIndex] = temp;
        }
        return wordArray;
    }         
}
        int[] numbers = {0,1,2,3,4,5,6,7,8,9};
        List<int> numList = new List<int>();
        numList.AddRange(numbers);

        Console.WriteLine("Original Order");
        for (int i = 0; i < numList.Count; i++)
        {
            Console.Write(String.Format("{0} ",numList[i]));
        }

        Random random = new Random();
        Console.WriteLine("\n\nRandom Order");
        for (int i = 0; i < numList.Capacity; i++)
        {
            int randomIndex = random.Next(numList.Count);
            Console.Write(String.Format("{0} ", numList[randomIndex]));
            numList.RemoveAt(randomIndex);
        }
        Console.ReadLine();