C# 如何从字典内容的特定范围中获取随机值

C# 如何从字典内容的特定范围中获取随机值,c#,dictionary,random,C#,Dictionary,Random,如果通过这种方式,我可以从给定范围中获得随机值: int r = ran.Next(1, 4); string v; if (dict.TryGetValue(r, out v)) { ///... } 如何正确地从特定范围获取词典内容的随机值,例如仅从4到6以及1和2,并避免查找3: Dictionary<int, string> dict = new Dictionary<int, string>() { { 1, "word1" },

如果通过这种方式,我可以从给定范围中获得随机值:

 int r = ran.Next(1, 4); 
 string v;
 if (dict.TryGetValue(r, out v))
 {
    ///...
 }
如何正确地从特定范围获取
词典内容的随机值,例如仅从4到6以及1和2,并避免查找3:

Dictionary<int, string> dict = new Dictionary<int, string>()
{
    { 1, "word1" },
    { 2, "word2" },
    { 3, "word3" },
    { 4, "word4" },
    { 5, "word5" },
    { 6, "word6" }
};
Dictionary dict=new Dictionary()
{
{1,“word1”},
{2,“word2”},
{3,“word3”},
{4,“word4”},
{5,“word5”},
{6,“word6”}
};

下面是一个使用扩展方法的解决方案:

public static class RandomExtensions
{
    public static int NextWithinRange(this Random random, params Range[] ranges)
    {
        if (ranges.Length > 0)
        {
            Range range = ranges[random.Next(0, ranges.Length)];
            return random.Next(range.MinValue, range.MaxValue + 1);
        }

        return random.Next();
    }

    public class Range
    {
        public int MinValue { get; set; }
        public int MaxValue { get; set; }

        public Range(int minValue, int maxValue)
        {
            MinValue = minValue;
            MaxValue = maxValue;
        }
    }
}
用法:

int r = ran.NextWithinRange(new Range(1, 2), new Range(4, 6));
string v;
if (dict.TryGetValue(r, out v))
{
    ///...
}

下面是一个使用LINQ的解决方案:

var rand = new Random();

// create a new dictionary, filtering out any unwanted keys within range(s)
Dictionary<int, string> filteredDict =
    dict.Where(pair => (pair.Key >= 1 && pair.Key <= 2)
                    || (pair.Key >= 4 && pair.Key <= 6))
        .ToDictionary(pair => pair.Key, pair => pair.Value);

// get a random entry from the filtered dictionary
KeyValuePair<int, string> entry = filteredDict.ElementAt(rand.Next(0, filteredDict.Count));

// get random entry's value
string value = entry.Value;
var rand=new Random();
//创建一个新字典,过滤掉范围内所有不需要的键
字典过滤器添加=
dict.Where(pair=>(pair.Key>=1&&pair.Key=4&&pair.Key-pair.Key,pair=>pair.Value);
//从筛选字典中获取随机条目
KeyValuePair entry=Filteredict.ElementAt(rand.Next(0,Filteredict.Count));
//获取随机项的值
字符串值=entry.value;

编辑:感谢@Kyle在我的第一篇博文中指出了潜在的
ArgumentOutOfRange
异常。

然后用排除的值创建哈希集

HashSet<int> excludedValues = ....
List<int> values = dict.Where(x=> excludedValues.Contains(x.Key) == false).Select(x=>x.Key).ToList();

int index = rand.Next(1, values.Count);
string value = dict[index];
HashSet excludedvalue=。。。。
List values=dict.Where(x=>excludedValues.Contains(x.Key)==false);
int index=rand.Next(1,value.Count);
字符串值=dict[索引];

通过这种方式,您不限于排除值3。您可以在此集合中放入任何内容。如果集合较大,则应使用比列表快得多的哈希集。

通常,在
LINQ
中有两个可用函数,即和

这些函数可用于获取任何
IEnumerable
的切片。请记住
Dictionary
也是
IEnumerable

所以要访问第4个和第10个元素之间的随机元素

var rand = new Random();
dict.Skip(3).Take(6 /* 10 - 4 */).ElementAt(rand.Next(6 /* 10 - 4 */)
现在请记住,序列不一定按键或任何可预测的方式进行排序或排序。您可能必须使用
OrderBy
按您选择的顺序遍历字典


如果您想在字典更新期间多次执行这些操作,那么您只需访问
dict.Keys.OrderBy().ToList()
,然后使用相同的
Skip().Take().ElementAt()访问此
List
或直接使用索引操作。这将避免多次重新枚举同一词典

您可以收集所有可以获取的值,然后从中随机选择一个:

   private static Random s_Random = new Random(); 

   ...

   var values = dict
      .Where(pair => pair.Key >= 4 && pair.Key <= 6 || // conditions on key
                     pair.Key >= 1 && pair.Key <= 2)
      .ToArray();

   var result = values[s_Random.Next(values.Length)];
private static Random s_Random=new Random();
...
var值=dict

其中(pair=>pair.Key>=4&&pair.Key=1&&pair.Key使用此解决方案,您可以在指定范围内获得随机值,而无需首先迭代字典

void Main()
{
    Dictionary<int, string> dict = new Dictionary<int, string>()
    {
        { 1, "word1" },
        { 2, "word2" },
        { 3, "word3" },
        { 4, "word4" },
        { 5, "word5" },
        { 6, "word6" }
    };
    var randomizer = new Random();
    GetRandomValue(dict, randomizer, new Range(4, 6), new Range(1,2)).Dump();
}

public TValue GetRandomValue<TValue>(IDictionary<int, TValue> dic, Random randomizer, params Range[] ranges)
{
    var range = ranges[randomizer.Next(0, ranges.Length)];
    var key = randomizer.Next(range.From, range.To + 1);
    return dic[key];
}

public class Range
{
    public Range(int @from, int to)
    {
        From = @from;
        To = to;
    }
    public int From {get;set;}
    public int To {get;set;}
}
void Main()
{
Dictionary dict=新字典()
{
{1,“word1”},
{2,“word2”},
{3,“word3”},
{4,“word4”},
{5,“word5”},
{6,“word6”}
};
var randomizer=new Random();
GetRandomValue(dict、随机化器、新范围(4,6)、新范围(1,2)).Dump();
}
公共TValue GetRandomValue(IDictionary dic、随机随机化器、参数范围[]范围)
{
var range=范围[randomizer.Next(0,ranges.Length)];
var key=randomizer.Next(range.From,range.To+1);
返回dic[键];
}
公共类范围
{
公共范围(int@from,int-to)
{
From=@From;
To=To;
}
来自{get;set;}的公共int
公共int到{get;set;}
}

根据具体需要,最简单的方法可能是指定可能的数字:

int[] a { 1, 2, 4, 5, 6 };

int r = a[ran.Next(a.Length)]; 


如何保证该范围内的所有值都存在于
字典中
如果可以,为什么不使用
数组
/
列表
来存储它,而不是
字典
@Vikhram您好,因为它不是一个更新的列表。是的,对于列表或数组,它是简单而有用的,但我想知道t dictionary如果可能的话。如果dictionary包含排除的键,则该操作可能会失败,因为所选的随机数可能大于剩余的键值对数。这将导致
ElementAt
抛出
ArgumentOutOfRange
异常。
int r = ran.Next(1, 6); 

if (r == 3) r = 6;