我有一个字典,其中键是枚举值列表,值是一个简单的字符串.
我需要做的是使用另一个枚举值列表找到匹配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]);
}