你能帮我找到一种随机化数组的方法吗?例如:Randomise整数数组
int[] arrayInt = { 1, 2, 3, 4, 5, 6, 7 };
随机化后,结果应该存储在另一个数组中。
而且当您再次随机化时,应该将它与存储在第二个数组中的值进行比较,如果该值存在,则程序必须再次随机化。
你能帮我找到一种随机化数组的方法吗?例如:Randomise整数数组
int[] arrayInt = { 1, 2, 3, 4, 5, 6, 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);
}
+1,但速度慢,orderby在O(n log n)中工作,可以在O(n)中完成shuffle – 2013-05-10 08:18:40
@ArsenMkrt:谢谢。在大多数情况下应该足够快。我猜你在遇到性能问题之前会得到一个'OutOfMemoryException'。此外,由于OP明确表示他想要新阵列,因此旧阵列的重组失去了重要性,因为它还需要首先创建新的阵列。 – 2013-05-10 08:25:19
在这两种情况下都应该分配新阵列,所以它不是这种情况。但是,是的,同意在大多数情况下,orderby就足够了。 – 2013-05-10 10:51:27
使用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();
由于随机实例在方法中初始化,因此不会创建随机数组。尝试在循环中创建多个数组。他们将使用与时间相同的种子,因此结果将是相同的数组。 – 2013-05-10 07:41:53
这演示了这个问题:http:// ideone。com/HXv9tn因此,将随机作为参数传递给方法(或将随机实例用作类字段)。 – 2013-05-10 08:00:48
yup ..这些事情发生在提交前没有运行代码。很难与你灵活的手指竞争:) – maxlego 2013-05-10 08:07:45
你的问题的第一部分是关于洗牌数组。一个好的算法是Fisher-Yates shuffle。
关于将结果与原始结果进行比较的下一部分更加模糊。我假设你想创建一个随机洗牌,保证所有元素都洗牌到一个新的位置。例如。
我已经创造了这样一些扩展(注意,这是与元素类型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();
的代码可以通过验证参数,并决定如何处理上述的非终止问题得到改善。
希望这会有所帮助。使用一个安全的加密提供商和比较安全散列 - 大材小用,可以随意调整使用:)
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());
}
}
}
排序依据是洗牌很好的方式提供者,但它使用的排序这是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]
伪代码虽然我同意这个心不是一个非常良好的措辞或研究的问题,我觉得它有点粗糙downvote一个全新的用户没有至少,关于如何提高一个解释他们的回答 – 2013-05-10 06:28:03
使用'Random'创建一个随机索引:'Random rand = new Random(); int randomIndex = rand.Next(0,arrayInt.Length);',稍后检查您的其他数组/列表以查看该项目是否存在于原始数组的该索引中。 – Habib 2013-05-10 06:30:15
SO有翻译吗?有时候,如果可以用自己的母语提问并由专业翻译人员翻译(他也熟悉上下文 - 本例中的C#或一般编程),那么感觉会更好。 – SimpleVar 2013-05-10 06:34:25