【发布时间】:2016-10-19 03:08:53
【问题描述】:
如果您使用Random.Range() 生成值,有什么方法可以排除该范围内的某些值(例如:选择1 到20 之间的数字,而不是6 到8 之间的数字)?
【问题讨论】:
-
您可以编写自己的方法来检查生成的数字是否在排除范围内,在这种情况下重新生成它。
-
我加了random标签,是为了把这个问题介绍给本站众多随机数专家,让我的回答有点可信度。
如果您使用Random.Range() 生成值,有什么方法可以排除该范围内的某些值(例如:选择1 到20 之间的数字,而不是6 到8 之间的数字)?
【问题讨论】:
最好的方法是使用你最喜欢的生成器生成一个介于 1 和 17 之间的整数 n,然后使用转换
if (n > 5){
n += 3;
}
如果您在 1 到 20 之间进行抽样,然后丢弃值,您可能会引入统计异常,特别是对于低差异序列。
【讨论】:
所以你实际上想要17 (20 - 3) 不同的值
[1..5] U [9..20]
你可以实现这样的东西:
// Simplest, not thread-safe
private static Random random = new Random();
...
int r = (r = random.Next(1, 17)) > 5
? r + 3
: r;
在一般(和复杂)的情况下,我建议生成一个包含所有可能值的数组,然后取 来自它的项目:
int[] values = Enumerable
.Range(1, 100) // [1..100], but
.Where(item => item % 2 == 1) // Odd values only
.Where(item => !(item >= 5 && item <= 15)) // with [5..15] range excluded
//TODO: Add as many conditions via .Where(item => ...) as you want
.ToArray();
...
int r = values[random.Next(values.Length)];
【讨论】:
是的,您可以在 LINQ 中简单地使用 where 语句
var list = Enumerable.Range(1, 20).Where(a => a < 6 || a > 8).ToArray();
没有 LINQ 的其他方式
public IEnumerable RangeBetween()
{
foreach (var i in Enumerable.Range(1, 20))
{
if (i < 6 || i > 8)
{
yield return i;
}
}
}
编辑:现在我看到不是一个严格的 C# 问题。它影响Unity 和Random。但是为了获得完整的答案,我建议您使用上面的代码和Enumerable.Range,然后使用它来生成数字:
list[Random.Next(list.Length)];
【讨论】:
IEnumerable(在 iOS 上存在问题),而在数组上却使用了。很有趣。
另一种方法是制作一个包含有效返回值的数组,然后随机选择一个:
void Main()
{
var rng = new Random();
var validValues = Enumerable.Range(1, 20).Except(new int[] {6, 7, 8}).ToArray();
for (int i = 0; i < 25; i++)
{
Console.Write(validValues[rng.Next(0, validValues.Length)]);
Console.Write(" ");
}
}
编辑:哎呀!刚刚注意到这是针对 Unity3D 的,所以这个例子可能不合适。不过,它使用标准的 Random 类工作。
【讨论】:
如果 r 在 6-8 范围内,这将选择一个不同的随机数。
int r = 0;
do
{
r = Random.Next(20);
} while (r >= 6 && r <= 8)
【讨论】:
我将在这个主题上投入 2 美分。这是一个完整的类,展示了一种生成随机数的方法,不包括您选择的数字以及如何使用它。
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
public class test2 : MonoBehaviour {
System.Random rand;
int[] excludelist;
void Start()
{
rand = new System.Random();
excludelist = new int[] { 5,9,3};
for(int i = 0; i<20;i++)
{
Debug.Log(MakeMeNumber(excludelist));
}
}
private int MakeMeNumber(params int[] excludeList)
{
var excluding = new HashSet<int>(excludeList);
var range = Enumerable.Range(1, 20).Where(i => !excluding.Contains(i));
int index = rand.Next(0, 20 - excluding.Count);
return range.ElementAt(index);
}
}
【讨论】:
我创建了一个专为该案例设计的资产(已付费)。
它只包含一些有用的函数,可以根据给定的间隔(例如,在 X 和 Y 之间,不包括 Z)生成随机数。
第三个函数 RandomExclude.RandomInt (int, int, Vector2) 将涵盖您的示例(1 到 20,但不包括 6 到 8)。第一个 int 是可能的最低值,第二个 int 是最高值,Vector2 是我们排除的区间。在您的情况下,它看起来像这样:
int ourOutcome = RandomExclude.RandomInt (1, 20, new Vector2 (6, 8));
资产包含更多类似的功能,它们让您生成一个不包括一个数字、几个数字或几个区间的 int。
资产本身已经涵盖了所有详细的实施说明,所以不用担心。
https://assetstore.unity.com/packages/tools/input-management/random-exclude-133786
请随意尝试!
【讨论】: