只有当它是唯一的时才返​​回随机数

时间:2011-01-05 15:32:28

标签: c# loops random

我的大脑今天正在融化,我想不出怎么做这么简单的代码。 numberList是一个由逗号分隔的数字字符串,如'2,34,10'等。当我请求一个随机数时,我需要检查字符串是否有数字,如果是,我想继续请求一个随机数,直到随机数绝对不在字符串中。我不知道我会采取什么样的循环来实现这个目的:

Random r = new Random();

public int RandomPos(int max) {
  int i;
  do {
    i = r.Next(max) + 1;
  }
  while (!numberList.Contains(i.ToString()));

    return i;
}

13 个答案:

答案 0 :(得分:2)

我只是用文本而不是代码来解释,因为我现在懒得编写代码:

  1. 使用String.Split将列表分成数组,然后(如果需要)将其解析为整数。
  2. 使用Enumerable.Range(0, max).ToArray()创建您可以选择的所有号码的列表。
  3. 从第二个列表中减去第一个列表。
  4. 从最终列表中随机选择一个元素。
  5. 这样做的好处是,您无需随机选择内容并在可能无限但未真正实践的循环中重试。

    编辑:这是一些代码

    string[] invalid = numberList.Split(", ");
    var list = Enumerable.Range(0, max).Where(x => !invalid.Contains(x.ToString())).ToArray();
    return list[r.Next(list.Count)];
    

答案 1 :(得分:1)

也许这就是你想要的?我使用了常规的while,因为我觉得它们更容易阅读,我认为你唯一错的就是!

public int RandomPos(int max) {
  int i = r.Next(max);
  var intList = numberList.Split(',').ToDictionary<string,int>((n) => int.Parse(n));
  while(intList.Contains(i))
  {
     i = r.Next(max);
  }
  return i;
}

假设我需要首先将numberList拆分为如果它们在字符串中。这将使第三行看起来像:

答案 2 :(得分:1)

删除!

  do 
  {
    i = r.Next(max) + 1;
  }
  while (numberList.Contains(i.ToString()));

答案 3 :(得分:1)

试试这个:

static string invalidNumbers = "0,1,2,3,4,5";
static Random random = new Random();

static int Randomize()
{
    var randomInt = random.Next(0, 10);
    if (!invalidNumbers.Split(',').Contains(randomInt.ToString()))
    {
        return randomInt;
    }
    else
    {
        return Randomize();
    }
}

答案 4 :(得分:1)

提供简单的答案,您不需要Split()。假设数字之间没有空格,相应地修改:

String modifiedNumberList = "," + numberList + ",";
do {
    i = r.Next(max) + 1;
}
while (modifiedNumberList.Contains("," + i.ToString() + ","));

编辑:我相信BrokenGlass也是对的,你不应该从我的解决方案中删除“!”。

答案 5 :(得分:0)

@ Dave回复的修改:

static string invalidNumbers = "0,1,2,3,4,5";
static Random random = new Random();

static int Randomize()
{

    var randomInt = random.Next(0, 10);
    var splitString = invalidNumbers.Split(',');

    while (splitString.Contains(randomInt.ToString()))
    {
        randomInt = random.Next(0, 10);
    }
    return randomInt;        
}

答案 6 :(得分:0)

// if numberList is large then use HashSet<int> rather than a plain int[] array
int[] nums = numberList.Split(new[] { ',', ' ' },
                              StringSplitOptions.RemoveEmptyEntries)
                       .Select(int.Parse)
                       .ToArray();

int i;
while (nums.Contains(i = r.Next(max) + 1));
return i;

(如果/ numberList包含rng可能产生的所有可能值,您还应该添加一个检查以确保不会以无限循环结束。)

答案 7 :(得分:0)

有几种改进方法:

1)使用List<int>或其他东西而不是字符串来让您的生活更轻松

2)如果max很小(比如说<1000或者其他),则生成所有可能值的列表,随机排序,并从该列表中依次返回数字。

当“使用”数字的数量接近“max”时,您可能会在获得未使用的数字之前以非常长的循环结束。对于最大值超过几百的值,这实际上可能是重要的。在您的情况下,这可能是也可能不是问题。

答案 8 :(得分:0)

此代码将涵盖所有情况:

  1. “1,2,3,4,5” ...
  2. “1,2,3,4,5”......

    private static int GetRandomNumber(string existingNumbers, int max)
    {
        string[] existingNumbersArray = existingNumbers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        List<string> existingNumbersList = new List<string>();
    
    
    
    foreach (string number in existingNumbersArray)
    {
        existingNumbersList.Add(number.Trim());
    }
    
    
    while (true)
    {
        Random rnd = new Random();
        int value = rnd.Next(max);
    
    
        if (!existingNumbersList.Contains(value.ToString()))
        {
            return value;
        }
    }
    
    }
  3. 你甚至可以拿出这部分:

    foreach (string number in existingNumbersArray)
    {
        existingNumbersList.Add(number.Trim());
    }
    
    
    while (true)
    {
        Random rnd = new Random();
        int value = rnd.Next(max);
    
    
        if (!existingNumbersList.Contains(value.ToString()))
        {
            return value;
        }
    }
    

    因此每次调用GetRandomNumber函数时都不会调用它。

答案 9 :(得分:0)

.Split将完成这项工作,以下代码也可以正常工作,只是为了好玩(替换代码中的行while (!numberList.Contains(i.ToString()));,而不是检查{{1} }检查i.ToString()加上开头和结尾。如果","+i.ToString()+","之后有空格,则需要调整它:

","

答案 10 :(得分:0)

我对所有其他答案的补充..

    const string invalidNumbers = "0,1,2,3,4,5";
    Random random = new Random();
    int value = 0;

    List<int> tmpList = new List<int>();
    foreach (var x in invalidNumbers.Split(','))
    {
        tmpList.Add(Int32.Parse(x));    
    }

    do
    {
        value = random.Next(0, 10);
    } 
    while (tmpList.Contains(value));

    return value

答案 11 :(得分:0)

编辑:误解了第一篇文章的问题,无论如何,这是一个递归的解决方案。

将数字保留在列表中似乎更好,但是如果需要遵循您提出的格式,这里是:

    const int MAX_ATTEMPTS = 10;
    Random r = new Random();
    string nlist = "2, 34, 10";

    public int RandomPos(int max_val)
    {
        List<string> used = nlist.Replace(" ","").Split(',').ToList();
        return _RandomPos(MAX_ATTEMPTS, max_val, used);
    }

    private int _RandomPos(int tl, int max, List<string> used)
    {
        if (tl <= 0)
            throw new Exception("Could not generate random number. Too many tries.");
        else
        {
            int rnum = r.Next(max);
            if (!used.Contains(rnum.ToString()))
            {
                nlist += ", " + rnum.ToString();
                return rnum;
            }
            else
                return _RandomPos(tl - 1, max, used);
        }
    }

答案 12 :(得分:0)

我意识到有很多条目,但我没有看到任何一些不错的错误检查。话虽如此,这将提供一些东西:

  • 没有什么可以取消资格时不会浪费任何努力
  • 只会从一系列可能的选择中进行选择
  • 如果在最大范围内无法选择号码而不在取消资格列表中,则会标记-1

所以这里是:

public int RandomPos(int max)
{
    // compile the list of numbers we need to disqualify
    List<int> disqualified = numberList.Split(new[]{',',' '},StringSplitOptions.RemoveEmptyEntries).Select(n => int.Parse(n)).ToList();

    // Nothing to check against, save the CPU cycles
    if (disqualified.Count == 0)
        return (new Random(DateTime.Now.Millisecond)).Next(max) + 1;

    // make a list of everything that's possible for a choice
    List<int> valid = Enumerable.Range(0, max).Where(r => !disqualified.Contains(r)).ToList();

    // return either a valid result, or -1 if there are no valid results
    return (valid.Count == 0 ? -1 : valid[(new Random(DateTime.Now.Millisecond)).Next() % valid.Count]);
}