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

时间:2017-06-07 15:19:15

标签: c# dictionary random

如果这样,我可以从给定范围获得随机值:

 int r = ran.Next(1, 4); 
 string v;
 if (dict.TryGetValue(r, out v))
 {
    ///...
 }

如何从特定范围正确获取<int, string>字典内容的随机值,例如仅从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" }
};

6 个答案:

答案 0 :(得分:0)

使用排除值创建HashSet,然后

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];

这样您不仅可以排除值3.您可以在此集合中添加任何内容。如果你的集合很大,你应该使用比List更快的hashset。

答案 1 :(得分:0)

一般情况下,LINQ中提供了一些功能,即IEnumerable.SkipIEnumerable.Take

这些函数可用于获取任何IEnumerable的切片。请注意,Dictionary<TKey, TValue>也是IEnumerable<KeyValuePair<TKey, TValue>>

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

var rand = new Random();
dict.Skip(3).Take(6 /* 10 - 4 */).ElementAt(rand.Next(6 /* 10 - 4 */)

现在请记住,序列不一定按键或以任何可预测的方式排序或排序。您可能必须使用OrderBy按您选择的顺序遍历字典。

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

答案 2 :(得分:0)

您可以收集所有可以采用的值,然后从中选择随机值:

   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)];

答案 3 :(得分:0)

使用此解决方案,您可以获得指定范围内的随机值,而无需首先迭代字典。

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;}
}

答案 4 :(得分:0)

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

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

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

int r = ran.Next(1, 6); 

if (r == 3) r = 6;

答案 5 :(得分:-1)

以下是使用扩展方法的解决方案:

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;
编辑:感谢@Kyle在我的帖子中指出了潜在的ArgumentOutOfRange例外。