2013-05-10 76 views
1

你能帮我找到一种随机化数组的方法吗?例如:Randomise整数数组

int[] arrayInt = { 1, 2, 3, 4, 5, 6, 7 }; 

随机化后,结果应该存储在另一个数组中。

而且当您再次随机化时,应该将它与存储在第二个数组中的值进行比较,如果该值存在,则程序必须再次随机化。

+13

伪代码虽然我同意这个心不是一个非常良好的措辞或研究的问题,我觉得它有点粗糙downvote一个全新的用户没有至少,关于如何提高一个解释他们的回答 – 2013-05-10 06:28:03

+0

使用'Random'创建一个随机索引:'Random rand = new Random(); int randomIndex = rand.Next(0,arrayInt.Length);',稍后检查您的其他数组/列表以查看该项目是否存在于原始数组的该索引中。 – Habib 2013-05-10 06:30:15

+0

SO有翻译吗?有时候,如果可以用自己的母语提问并由专业翻译人员翻译(他也熟悉上下文 - 本例中的C#或一般编程),那么感觉会更好。 – SimpleVar 2013-05-10 06:34:25

回答

7

下面是使用Enumerable.OrderBy来订购具有random变量的输入数组的一种方法。生成新的序列后,它会与SequenceEqual输入数组进行比较:

public static T[] UniqueRandomArray<T>(T[] input, Random rnd) 
{ 
    if (input.Length <= 1) throw new ArgumentException("Input array must have at least two elements, otherwise the output would be the same.", "input"); 
    IEnumerable<T> rndSeq; 
    while (input.SequenceEqual(rndSeq = input.OrderBy(x => rnd.Next()))); 
    return rndSeq.ToArray(); 
} 

此示例代码生成被添加到列表10个新的阵列。这是确保新阵列是前一个不同:

Random rnd = new Random(); 
List<int[]> randomArrays = new List<int[]>(); 
int[] arrayInt1 = { 1, 2, 3, 4, 5, 6, 7 }; 
randomArrays.Add(arrayInt1); 

for (int i = 0; i < 10; i++) 
{ 
    int[] lastArray = randomArrays[randomArrays.Count - 1]; 
    int[] randomArray = UniqueRandomArray(lastArray, rnd); 
    randomArrays.Add(randomArray); 
} 

Demo

+0

+1,但速度慢,orderby在O(n log n)中工作,可以在O(n)中完成shuffle – 2013-05-10 08:18:40

+0

@ArsenMkrt:谢谢。在大多数情况下应该足够快。我猜你在遇到性能问题之前会得到一个'OutOfMemoryException'。此外,由于OP明确表示他想要新阵列,因此旧阵列的重组失去了重要性,因为它还需要首先创建新的阵列。 – 2013-05-10 08:25:19

+0

在这两种情况下都应该分配新阵列,所以它不是这种情况。但是,是的,同意在大多数情况下,orderby就足够了。 – 2013-05-10 10:51:27

1

使用LINQ

 Random rand = new Random(); 
     int[] arrayInt = 
      new[] {1, 2, 3, 4, 5, 6, 7}.Select(x => new {x, r = rand.Next()}) 
             .OrderBy(x => x.r) 
             .Select(x => x.x) 
             .ToArray(); 

,你可以随机任何类型的这样

public static class RandomExt 
{ 
    public static T[] RandomizeOrder<T>(this T[] array) 
    { 
     var rand = new Random(); 
     return array.Select(x => new {x, r = rand.Next()}) 
             .OrderBy(x => x.r) 
             .Select(x => x.x) 
             .ToArray(); 
    } 
} 

int[] arrayInt = new[] {1, 2, 3, 4, 5, 6, 7}.RandomizeOrder(); 
+1

由于随机实例在方法中初始化,因此不会创建随机数组。尝试在循环中创建多个数组。他们将使用与时间相同的种子,因此结果将是相同的数组。 – 2013-05-10 07:41:53

+0

这演示了这个问题:http:// ideone。com/HXv9tn因此,将随机作为参数传递给方法(或将随机实例用作类字段)。 – 2013-05-10 08:00:48

+0

yup ..这些事情发生在提交前没有运行代码。很难与你灵活的手指竞争:) – maxlego 2013-05-10 08:07:45

0

你的问题的第一部分是关于洗牌数组。一个好的算法是Fisher-Yates shuffle

关于将结果与原始结果进行比较的下一部分更加模糊。我假设你想创建一个随机洗牌,保证所有元素都洗牌到一个新的位置。例如。

  • [0,1,2] => [1,2,0]是确定的,但
  • [0,1,2] => [2,1,0]是不行因为1保持在地方

我已经创造了这样一些扩展(注意,这是与元素类型T一个通用的解决方案):

static class EnumerableExtensions { 

    static Random random = new Random(); 

    public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source) { 
    var list = source.ToList(); 
    for (var k = 0; k < list.Count; k += 1) { 
     var j = random.Next(k, list.Count); 
     Swap(list, k, j); 
    } 
    return list; 
    } 

    public static IEnumerable<T> RandomizeUniquely<T>(this IEnumerable<T> source) { 
    while (true) { 
     var randomized = source.Randomize(); 
     var isNotUnique = source 
     .Zip(randomized, (a, b) => Equals(a, b)) 
     .Any(equal => equal); 
     if (!isNotUnique) 
     return randomized; 
    } 
    } 

    static void Swap<T>(IList<T> list, Int32 i, Int32 j) { 
    var temp = list[i]; 
    list[i] = list[j]; 
    list[j] = temp; 
    } 

} 

Randomize方法实现了费雪耶茨洗牌。 RandomizeUniquely使用这种方法并试图创建一个满足上述条件的洗牌。该方法只是尝试,直到找到满意的洗牌。请注意,此算法可能不会终止。例如。如果源只有一个元素,则不能找到唯一的随机播放。另外,如果源包含重复项,解决方案可能不存在。

要使用方法简单地调用它是这样的:

var randomized = Enumerable.Range(1, 7).RandomizeUniquely(); 

的代码可以通过验证参数,并决定如何处理上述的非终止问题得到改善。

0

希望这会有所帮助。使用一个安全的加密提供商和比较安全散列 - 大材小用,可以随意调整使用:)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Security.Cryptography; 
using System.Collections; 
using System.Collections.Concurrent; 

namespace RandomiseArray 
{ 
    static class Program 
    { 
     static void Main(string[] args) 
     { 
      // source array 
      string[] s = new string[] { "a", "b", "c", "d", "e", "f", "g" }; 

      // number of unique random combinations required 
      int combinationsRequired = 5; 
      var randomCombinations = s.Randomise(System.Text.UnicodeEncoding.Unicode.GetBytes, combinationsRequired); 

      foreach (var c in randomCombinations) 
       Console.WriteLine(c.Aggregate((x, y) => x + "," + y)); 

      Console.ReadLine(); 
     } 

     /// <summary> 
     /// given a source array and a function to convert any item in the source array to a byte array, produce x unique random sequences 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     /// <param name="source"></param> 
     /// <param name="byteFunction"></param> 
     /// <param name="x"></param> 
     /// <returns></returns> 
     public static IEnumerable<IEnumerable<T>> Randomise<T>(this IEnumerable<T> source, Func<T, byte[]> byteFunction, int x) 
     { 
      var foundValues = new ConcurrentDictionary<byte[], T[]>(); 
      int found = 0; 
      do 
      { 
       T[] y = source.Randomise().ToArray(); 
       var h = y.Hash(byteFunction); 
       if (!foundValues.Keys.Contains(h)) 
       { 
        found++; 
        foundValues[h] = y; 
        yield return y;   // guaranteed unique combination (well, within the collision scope of SHA512...) 
       } 
      } while (found < x); 
     } 

     public static IEnumerable<T> Randomise<T>(this IEnumerable<T> source) 
     { 
      using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) 
       return source.OrderBy(i => rng.Next()); 
     } 

     public static int Next(this RNGCryptoServiceProvider rng) 
     { 
      byte[] buf = new byte[4]; 
      rng.GetBytes(buf); 
      return BitConverter.ToInt32(buf, 0); 
     } 

     public static byte[] Hash<T>(this IEnumerable<T> items, Func<T, byte[]> getItemBytes) 
     { 
      using (SHA512CryptoServiceProvider sha = new SHA512CryptoServiceProvider()) 
       return sha.ComputeHash(items.SelectMany(i => getItemBytes(i)).ToArray()); 
     } 
    } 
} 
0

排序依据是洗牌很好的方式提供者,但它使用的排序这是O(n日志N )。随机播放可以在O(n)中完成。

这里是wikipedia

for i from n − 1 downto 1 do 
     j ← random integer with 0 ≤ j ≤ i 
     exchange a[j] and a[i]