C#中的随机数生成器 - 唯一值

时间:2010-02-28 14:27:28

标签: c# arrays random

我在C#中忙于编码数组。我可以用随机生成器填充它,但现在我的问题是如何做到这一点,但我可以检查数值是否已经在数组中,如果是这样,生成一个新的值

额外信息:
最大值:100
元素数量:100

重要的PLZ在我的想法中继续工作

我的想法

public void FillArray(int[] A, int Range)
{
    for (int I = 0; I < A.Length; I++)
    {
        A[I] = ValidNumber(T, I, Range);
    }
} /* Fill Array */

选择排序的实施

public void SelectionSort(int[] A)
{
    int K, X;
    for (int I = 0; I < A.Length - 1; I++)
    {
        K = I;
        X = A[K];
        for (int J = I + 1; J < A.Length; J++)
        {
            if (A[J] < X)
            {
                K = J;
                X = A[K];
            }
        }
        A[K] = A[I];
        A[I] = X;
    }
} /* Selection sort */

这些只是一些想法现在我想知道我怎么能解决它所以我可以看看选择排序如果有所有那里(fillarray)是相同的,如果是这样用新的随机值替换它。所以我想创建一个带有整数的随机数组 - 从1到100以随机顺序

5 个答案:

答案 0 :(得分:30)

  

我该如何做,但这样我可以检查数值是否已经在数组中,如果是,则生成新值

你不会这样做,因为这是一个非常糟糕的主意

为了说明为什么这是一个糟糕的主意,请考虑同一问题的另一个版本:通过以下过程将一百万个数字排序为随机顺序:

  1. 选择一到一百万的数字。
  2. 检查它是否已在列表中。
  3. 如果是,请返回步骤1
  4. 否则,请将号码添加到列表中。
  5. 列表上有一百万个项目吗?如果是的话,你就完成了。如果没有,请返回步骤1.
  6. 显然这很有效。这是个好主意吗?我们假设你差不多完成了。该清单上有999999件物品。唯一缺少的项目是857313.你做什么?您可以选择一个随机数,例如12.现在,检查列表中的999999个项目,看看它们中是否有12个.12可能是您选择的第一个数字之一,因此可能很快找到它。或者它可能是最后一个,所以需要很长时间。平均而言,将需要500000次检查以查看列表中是否有12个。它是,因为列表中只缺少一个数字。

    12没有成功。回到开头。选择另一个随机数,比如53259.列表上有这个吗?另外50万支票。

    继续这样做,直到你生成857313,每百万次尝试就会发生一次。

    因此,平均而言,将最后一项放在列表中需要500000 x 1000000 =五千亿比较。它可能会更多。可能需要几万亿次比较。或者你可能会很幸运,需要一个。但平均而言,有五万亿的比较。

    这是一种产生列表随机排序的糟糕的方式。

    有两种很好的方法可以对列表进行随机排序。

    (1)制作一个可以对给定排序功能的列表进行排序的设备。提供基于随机种子的稳定排序。

    请注意,当“是否大于B?”时,通过创建一个返回随机结果的方法,会产生随机排序。这是一个不稳定的顺序;许多排序算法都基于稳定的排序顺序,并且在给定不稳定的排序顺序时将进入无限循环或具有其他不良行为。

    这个算法是O(n lg n),具有很好的特性,很容易用标准部分写出来,正如其他答案所示。对于典型实现中的小型列表,它也非常快。

    (2)随机选择源列表中的索引项,从源列表中删除,然后将其放在目标列表中。

    后者被称为Knuth Shuffle或Fischer-Yates Shuffle,它是一种非常快速的算法。您可以“就地”执行此操作,将现有数组变为洗牌顺序,或者创建新列表。它还有一个很好的属性,你可以“支付游戏费用”,根据需要改变列表的“顶部”。如果你有一百万件要洗牌,但你只需要前一百件,你就可以计算出前一百件的排序顺序并称之为好。

答案 1 :(得分:7)

以下将以随机顺序生成一个数字为1-100的数组。

    Random rnd = new Random();
    var randomNumbers = Enumerable.Range(1, 100).OrderBy(i => rnd.Next()).ToArray();

答案 2 :(得分:5)

根据你的描述我认为你需要一个100个整数的数组,其值从1到100并且没有重复的数字。如果数字是整数,则不需要生成随机数,因为所有可能的数字都在数组中。因此,只有订单或数字可以随机化。

使用Linq和Jesper Palm的方法 - 与Thomas Levesque一起使用以下语句将为您提供所需的数组。

Random rnd = new Random();
var randomNumbers = Enumerable.Range(1, 100)
                              .Select(x => new { val = x, order = rnd.Next() })
                              .OrderBy(i => i.order)
                              .Select(x => x.val)
                              .ToArray();

该方法甚至非常快,绝对比任何比较操作更有效。

要在原始海报上解释上述内容,请参阅以下评论:

  • Enumerable.Range(1, 100)创建一个从1开始到100结束的整数范围。
  • .Select(x => new { val = x, order = rnd.Next() })创建一个新的临时对象,其中包含值和订单位置,该位置由随机数确定。
  • .OrderBy(i => i.order)按顺序排列临时对象。
  • .Select(x => x.val)选择临时对象的值,从而转换回int。
  • .ToArray()再次将整个事物转回数组。

使用的语法是LINQ,它在.NET 3.5中可用。对于旧版本,您必须自己实现它,这要复杂得多,而且要长得多。

在Eric的评论之后:如果需要改组,您可以按照以下方式执行代码

var list = myInputList;
var result = list.Select(x => new { val = x, order = rnd.Next() })
                 .OrderBy(i => i.order)
                 .Select(x => x.val)
                 .ToArray();

答案 3 :(得分:2)

这是一个天真的实现:

int[] values = new int[100];
Random random = new Random();
for(int i = 0; i < values.Length; i++)
{
    int v;
    do
    {
        v = random.Next(100) + 1;
    } while (Array.IndexOf(values, v) != -1)
    values[i] = v;
}

但效率非常低,特别是在数组末尾......

更好的解决方案是考虑到这一点,因为你需要以随机顺序从1到100的100个不同的值,你的数组最终将包含从1到100的所有可能值。所以你只需要生成这些值的序列价值观,并“洗牌”它:

int[] values = Enumerable.Range(1, 100).ToArray();
Random random = new Random();
for(int i = values.Length - 1; i > 0; i--)
{
    int j = random.Next(i + 1);
    int tmp = values[i];
    values[i] = values[j];
    values[j] = tmp;
}

编辑:一种更好的方法,适用于不太具体的情况:

T[] RandomCombinationWithNoRepeat<T>(IEnumerable<T> itemsToPickFrom, int numberOfItemsToPick)
{
    // Copy original items to pick from, because we need to modify it
    List<T> itemsCopy = new List<T>(itemsToPickFrom);
    T[] array = new T[numberOfItemsToPick];
    Random random = new Random();
    for(int i = 0; i < numberOfItemsToPick; i++)
    {
        // Pick item and remove it from list
        int index = random.Next(itemsCopy.Count);
        array[i] = itemsCopy[index];
        itemsCopy.RemoveAt(index);
    }
    return array;
}

在你的情况下,你会像那样使用它:

int[] result = RandomCombinationWithNoRepeat(Enumerable.Range(1, 100), 100);

答案 4 :(得分:0)

从我的理解。您需要一组带有随机数的整数。我假设使用int数组或者List of int无所谓。 这是一个简单的完整方法,您已经描述过了。
using System; using System.Collections.Generic; using System.Text;

namespace FillRandom { class Program { static void Main(string[] args) { int minValue = 1; int maxValue = 100; //create a list of int with capacity set as 100 List array = new List(100);

        FillArray(array, minValue, maxValue, array.Capacity);

        //print out all values in the array
        foreach (int i in array)
        {
            Console.WriteLine(i);
        }
    }

    private static void FillArray(List<int> array, int minValue, int maxValue, int capacity)
    {
        int count = 0;
        while (array.Count != capacity - 1)
        {
            Random rnd = new Random();
            int value = rnd.Next(minValue, maxValue);
            if (!array.Contains(value))
            {
                array.Add(value);
            }
            count++;
        }
        //print out the number of times the looping occurs
        Console.WriteLine("count: "+count);
    }        
}

FillArray(array, minValue, maxValue, array.Capacity); //print out all values in the array foreach (int i in array) { Console.WriteLine(i); } } private static void FillArray(List<int> array, int minValue, int maxValue, int capacity) { int count = 0; while (array.Count != capacity - 1) { Random rnd = new Random(); int value = rnd.Next(minValue, maxValue); if (!array.Contains(value)) { array.Add(value); } count++; } //print out the number of times the looping occurs Console.WriteLine("count: "+count); } }

您可以创建一个控制台项目并尝试一下。