C# 如何从范围中获取随机数,不包括某些值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18484577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 12:21:25  来源:igfitidea点击:

How to get a random number from a range, excluding some values

c#random

提问by tenthplanet0

In C#, how do I get a random number from a range of values - like 1..100, but that number should not be in some specific list of values, like 5, 7, 17, 23?

在 C# 中,如何从一系列值中获取随机数 - 例如 1..100,但该数字不应该出现在某些特定的值列表中,例如 5、7、17、23?

采纳答案by Bridge

Since no-one has posted any example code:

由于没有人发布任何示例代码:

private int GiveMeANumber()
{
    var exclude = new HashSet<int>() { 5, 7, 17, 23 };
    var range = Enumerable.Range(1, 100).Where(i => !exclude.Contains(i));

    var rand = new System.Random();
    int index = rand.Next(0, 100 - exclude.Count);
    return range.ElementAt(index);
}

Here's the thinking:

思路如下:

  1. Build a Hashset of numbers you want to exclude
  2. Create a collection of all the numbers 0-100 which aren't in your list of numbers to exclude with a bit of LINQ.
  3. Create a random object.
  4. Use the Random object to give you a number between 0 and the number of elements in your range of numbers (inclusive).
  5. Return the number at that index.
  1. 构建要排除的数字的哈希集
  2. 创建一个包含所有数字 0-100 的集合,这些数字不在您的数字列表中,用一点 LINQ 排除。
  3. 创建一个随机对象。
  4. 使用 Random 对象为您提供一个介于 0 和您的数字范围内的元素数(含)之间的数字。
  5. 返回该索引处的数字。

回答by kol

Put the allowed numbers into an array, generate a random integer from 0 to the length of this array minus one. Use this integer as an index to get the random number itself from the array of allowed numbers.

将允许的数字放入一个数组中,生成一个从 0 到该数组长度减 1 的随机整数。使用此整数作为索引从允许的数字数组中获取随机数本身。



If the original array contains large objects instead of numbers, then making another array by deep copying the allowed objects won't be effective. In this case, the array of allowed objects should contain only a pointer, a reference, or an index to the objects in the original array. In this case you generate a random integer to select one element of this array, and use this pointer/reference/index to get the selected object itself from the originalarray.

如果原始数组包含大对象而不是数字,则通过深度复制允许的对象来创建另一个数组将无效。在这种情况下,允许的对象数组应该只包含指向原始数组中对象的指针、引用或索引。在这种情况下,您生成一个随机整数来选择此数组的一个元素,并使用此指针/引用/索引从原始数组中获取所选对象本身。

Hereis a working example for the general case (just one possible solution!):

是一般情况下的工作示例(只是一种可能的解决方案!):

using System;
using System.Collections.Generic;

public static class RandomElementSelector
{
    public static IList<T> CollectAllowedElements<T>(IList<T> allElements, IList<T> excludedElements)
    {
        List<T> allowedElements = new List<T>();
        foreach (T element in allElements)
            if (!excludedElements.Contains(element))
                allowedElements.Add(element);
        return allowedElements;
    }

    public static T SelectRandomElement<T>(IList<T> allowedElements)
    {
        Random random = new Random();
        int randomIndex = random.Next(allowedElements.Count);
        return allowedElements[randomIndex];
    }

    public static T SelectRandomElement<T>(IList<T> allElements, IList<T> excludedElements)
    {
        IList<T> allowedElements = CollectAllowedElements(allElements, excludedElements);
        return SelectRandomElement(allowedElements);
    }
}

public class Test
{
    public static void Main()
    {
        const int N = 100;

        // Example #1
        int[] allNumbers = new int[N];
        for (int i = 0; i < allNumbers.Length; ++i)
            allNumbers[i] = i + 1;
        int[] excludedNumbers = { 5, 7, 17, 23 };
        Console.WriteLine(RandomElementSelector.SelectRandomElement(allNumbers, excludedNumbers));

        // Example #2
        List<string> allStrings = new List<string>();
        for (int i = 0; i < N; ++i)
            allStrings.Add("Item #" + (i + 1));
        string[] excludedStrings = { "Item #5", "Item #7", "Item #17", "Item #23" };
        Console.WriteLine(RandomElementSelector.SelectRandomElement(allStrings, excludedStrings));
    }
}

回答by stmfunk

Create an array containing all the numbers you want (or whatever container your language uses) minus all the number you don't want and select at random from the array.

创建一个包含您想要的所有数字(或您的语言使用的任何容器)减去所有您不想要的数字的数组,然后从数组中随机选择。

回答by Saint

Use a function to generate random numbers between 1 and 100, than write an if statement e.g. if random number is equal to 5, 7, 17, 23, generate the random number again, else use the random number that was generated in the first place.

使用函数生成 1 到 100 之间的随机数,然后编写 if 语句,例如,如果随机数等于 5、7、17、23,则再次生成随机数,否则使用最初生成的随机数.

回答by Maher Manoubi

This is what I do in this situation, it's not perfect but works well for me. I usually do it only for 1 number but this is how it can be for a group of excluded numbers:

这就是我在这种情况下所做的,它并不完美,但对我来说效果很好。我通常只为 1 个号码执行此操作,但这就是一组排除号码的处理方式:

Let's say I want to exclude [5, 7, 17, 23] from a random between 1-100. I always have a substitution for each of the excluded numbers such as [6, 8, 18, 24]. If the random number falls into any of the excluded numbers, I replace it with its substitution.

假设我想从 1-100 之间的随机数中排除 [5, 7, 17, 23]。我总是替换每个排除的数字,例如 [6, 8, 18, 24]。如果随机数落入任何排除的数字中,我用它的替代品替换它。

I came here looking for a better solution but I couldn't find any so I ended up sharing mine.

我来到这里寻找更好的解决方案,但找不到任何解决方案,因此我最终分享了我的解决方案。

回答by Voicu

If you care about Big O, check out this algorithm. It assumes that the excluded values array is sorted in ascending order and contains values within 0and n-1range (inclusive).

如果您关心Big O,请查看此算法。它假定排除的值阵列被按升序排序,并且包含内的值0n-1范围(含)。

public static int random_except_list(int n, int[] x) 
{
    Random r = new Random();
    int result = r.Next(n - x.Length);

    for (int i = 0; i < x.Length; i++) 
    {
        if (result < x[i])
            return result;
        result++;
    }
    return result;
}

If you call it with:

如果你用以下方式调用它:

random_except_list(8, new int[]{3,4,6})

it will return one of the following values: 0, 1, 2, 5, 7.

它将返回以下值之一:0, 1, 2, 5, 7

回答by Ahmed Mansy

you can use a do-while statement to pick another Random if it equals what number you want to exclude. this code is to exclude the number you picked before

如果它等于要排除的数字,则可以使用 do-while 语句选择另一个 Random 。此代码用于排除您之前选择的数字

    int newNumber;
do {
    newNumber = Random.Range (0, 100);
} while(number == newNumber);

number = newNumber;

回答by Mayer Spitzer

This is the Extention method I use:

这是我使用的扩展方法:

Random random = new Random();
public static int RandomNumber(int minN, int maxN, IEnumerable<int> exNumbers)
    {
        int result = exNumbers.First(); 
        while (exNumbers.ToList().Contains(result))
        {
            result = random.Next(minN, maxN + 1);
        }
        return result;
    }