c# – 从Dictionary中找到匹配的KVP,字符串>其中搜索键是List并返回反向部分匹配

我有一个字典,其中键是枚举值列表,值是一个简单的字符串.

我需要做的是使用另一个枚举值列表找到匹配KVP.

这里发布的曲线球和原因是,如果我的测试或搜索列表中的列表包含字典中任何键中的所有项(或枚举对象),我还需要它返回KVP.

示例摘录代码:

public enum fruit{ apple , orange , banana , grapes };
public class MyClass
{
    public Dictionary<List<fruit>, string> FruitBaskets = new Dictionary<List<fruit>, string>;
    FruitBaskets.Add(new List<fruit>{apple,orange},"Basket 1");

    List<fruit> SearchList = new List<fruit>{orange,apple,grapes};
}

我需要在字典中搜索SearchList并返回“Basket 1”.

请注意,匹配可能比您对此类示例的预期要落后,因为我需要将密钥再次匹配搜索列表,反之亦然,因此搜索列表中不在密钥中的额外项目是可以的.

我知道我可以简单地迭代dict并逐个检查,但我也需要尽可能快,因为它驻留在一个运行得相当快的循环中.

我目前使用的是;

public Dictionary<List<fruit>, string> SearchResults;
foreach (KeyValuePair<List<fruit>, string> FruitBasket in FruitBaskets)
{
    if (FruitBasket.Key.Except(SearchList).Count() == 0)
        SearchResults.Add(FruitBasket);
}

想知道是否有更好/更快的方式.

最佳答案 你需要重新考虑你在字典中选择键. List键存在一些主要问题,例如:

>您不能对List使用O(1)键查找
>您的密钥不是一成不变的
>您可以将相同的列表作为键而不会收到错误,例如,您可以:

var a = new[] { fruit.organge }.ToList();
var b = new[] { fruit.organge }.ToList();
fruitBasket.Add(a, "1");
fruitBasket.Add(b, "2");

但这本字典有效吗?我猜不是,但这取决于你的要求.

>您可以更改字典键!

因此,您需要更改字典键类型.您可以使用组合的枚举值,而不是使用带有按位运算符的List.为此,您需要为每个枚举值分配2的幂:

[Flags]
public Enum Fruit
{
   Orange = 1,
   Apple = 2,
   Banana = 4,
   Grape = 8
}

您必须组合这些枚举值以获得所需的多值枚举字典键效果:

对于[Fruit.Orange,Fruit.Apple],你使用Fruit.Orange | Fruit.Apple.

以下是组合和分解值的示例代码:

    private static fruit GetKey(IEnumerable<fruit> fruits)
    {
        return fruits.Aggregate((x, y) => x |= y);
    }

    private static IEnumerable<fruit> GetFruits(fruit combo)
    {
        return Enum.GetValues(typeof(fruit)).Cast<int>().Where(x => ((int)combo & x) > 0).Cast<fruit>();
    }

现在您需要一个函数来获取SearchList的所有组合(幂集):

    private static IEnumerable<fruit> GetCombinations(IEnumerable<fruit> fruits)
    {
        return Enumerable.Range(0, 1 << fruits.Count())
            .Select(mask => fruits.Where((x, i) => (mask & (1 << i)) > 0))
            .Where(x=>x.Any())
            .Select(x=> GetKey(x));
    }

使用这些组合,您可以使用O(1)时间从字典中查找值.

var fruitBaskets = new Dictionary<fruit, string>();

fruitBaskets.Add(GetKey(new List<fruit> { fruit.apple, fruit.orange }), "Basket 1");

List<fruit> SearchList = new List<fruit> { fruit.orange, fruit.apple, fruit.grapes };

foreach (var f in GetCombinations(SearchList))
{
    if (fruitBaskets.ContainsKey(f))
        Console.WriteLine(fruitBaskets[f]);
}
点赞