根据值从字典中随机选取条目

本文关键字:随机 选取 字典 | 更新日期: 2023-09-27 18:18:07

我有一个包含餐馆和餐馆类型的字典:Dictionary<Restaurant, string>其中餐馆是我的类,为了简单起见,我使用字符串作为我的餐馆类型。

假设我的列表中有25个条目,其中可以有3个,4个或5个相同类型的餐厅。现在我想把范围缩小到每个类型随机选择1个元素。

我找到了这个页面,它解释了如何从字典中选择随机值,但是我如何去选择每个分组类型的随机条目?

让我知道如果我需要详细说明或如果你需要额外的信息!

编辑:我的代码示例:
Dictionary<Restaurant, string> restaurants = new Dictionary<Restaurant, string>();
randomRestaurants.Add(restaurants.GroupBy(x => x.string).//Randomly pick an entry per grouping and add it to list//
List<Restaurant> randomRestaurants = new List<Restaurant>();

示例:可能的类型有:ItalianFast foodSushi

我很抱歉又问了一个令人困惑的问题。

根据值从字典中随机选取条目

第一个想法(对于此列表的任何用法)是将数据源排序为更合理的格式,即键值结构,其中键类型是标识餐馆子集(字符串)的东西,值是其中的餐馆列表。

您可以使用类似于以下的代码来完成此操作:

var sensibleDict = sillyDict
    .GroupBy(kv => kv.Value)
    .ToDictionary(
        m => m.Key,
        m => m.Select(kv => kv.Key).ToList());

现在,我们可以简单地随机化结果,并将随机化后的第一个结果转换为Key => Single Value项。

var randomDict = sillyDict
    .GroupBy(kv => kv.Value)
    .ToDictionary(
        m => m.Key,
        m => m.Select(kv => kv.Key)
            .OrderBy(k => Guid.NewGuid())
            .Take(1)
            .First());

这将得到一个Dictionary<string, Restaurant>,其中第一个字符串是食物的类型(即。意大利语,寿司),第二个是随机的Restaurant

注意:正如我在评论中所说的,如果你的数据集很大,这不是排序列表的最有效方法。要了解更好的打乱列表的方法,请看下面的答案——随机化列表。

试试:

var restaurants = new Dictionary<string, List<Restaurant>();
//when u want to add a restaurant do this way:
var restaurant = new Restaurant { Type = "Sushi" };
List<Restaurant> res;
if(restaurants.TryGet(restaurant.Type, out res){
 res.Add(restaurant);
}
else restaurants.Add(restaurant.Type, new List<Restaurant> { restaurant });
// get random from a type
List<Restaurant> res2;
var type = "Sushi";
if(restaurants.TryGet(type, out res2){
 return res2[rand.Next(res2.Count)]
}

根据您提供的链接,您可以使用使用IGrouping而不是Dictionary(顺便说一下)的扩展方法。为什么要以这种方式使用Dictionary,仅仅将属性RestaurantType添加到Restaurant类不是更简单吗?

public static class Ext
{
    public static IEnumerable<TValue> RandomValues<TKey, TValue>(this IGrouping<TKey, TValue> grouping, int count)
    {
        Random rand = new Random();
        List<TValue> values = grouping.ToList();
        int size;
        while (count>0 && values.Count>0)
        {
            size = values.Count;
            var v = values[rand.Next(size)];
            values.Remove(v);
            count--;
            yield return v;
        }
    }
}

使用代码:

       // example data
       Dictionary<Restaurant, string> restaurants = new Dictionary<Restaurant, string>();
        restaurants.Add(new Restaurant("r1") ,"A");
        restaurants.Add(new Restaurant("r2") ,"B");
        restaurants.Add(new Restaurant("r3") ,"A");
        restaurants.Add(new Restaurant("r4") ,"B");
        restaurants.Add(new Restaurant("r5") ,"A");
        restaurants.Add(new Restaurant("r6") ,"B");
        restaurants.Add(new Restaurant("r7") ,"A");
        restaurants.Add(new Restaurant("r8") ,"B");
        // 3 Random restaurants from group "A"
        List<Restaurant> randomRestaurants = restaurants.GroupBy(a=>a.Value).FirstOrDefault(a=>a.Key=="A")
            .RandomValues(3).Select(x=>x.Key).ToList();
        randomRestaurants.Clear();
        // 1 random restaurant per group
         List<Restaurant> randomRestaurants2 = restaurants
             .GroupBy(a => a.Value)
             .Select(a => a.RandomValues(1).FirstOrDefault().Key)
             .ToList();
         // or, with SelectMany, 2 random restaurants per type:
              List<Restaurant> randomRestaurants3 = restaurants.GroupBy(a => a.Value)
             .SelectMany(a => a.RandomValues(2))
             .Select(d=>d.Key).ToList();