我的代码中有一个Dictionary<string, List<int>>
我正在使用以下方式:
Key Values
2011-07-15 1, 2, 3
2011-07-20 4, 5, 6
2010-02-11 7, 8, 9
我的代码需要能够查询与键中特定子字符串匹配的所有值。例如,如果我有子串2011-07
,它应该返回值{1, 2, 3, 4, 5, 6}
。 11
的子字符串应返回1-9
的所有ID。
有人可以推荐一种简洁的方法来实现这一目标吗?或者提供更好的数据结构来检索这些信息?
答案 0 :(得分:9)
我会做一个扩展方法:
public static class DictionaryExt
{
public static IEnumerable<T> PartialMatch<T>(this Dictionary<string, T> dictionary, string partialKey)
{
// This, or use a RegEx or whatever.
IEnumerable<string> fullMatchingKeys =
dictionary.Keys.Where(currentKey => currentKey.Contains(partialKey));
List<T> returnedValues = new List<T>();
foreach (string currentKey in fullMatchingKeys)
{
returnedValues.Add(dictionary[currentKey]);
}
return returnedValues;
}
}
向字典中添加值的“成本”不会改变,但检索的成本会更高,但只有当您知道自己正在进行部分匹配时才会发生。
顺便说一句,我相信你可以用一个Lambda表达式来改变它,但概念保持不变。
编辑:在您的示例中,此方法将返回2个值列表,但您可以更改它以合并列表。以下是您可以执行的扩展方法:
public static IEnumerable<T> PartialMatch<T>(
this Dictionary<string, IEnumerable<T>> dictionary,
string partialKey)
{
// This, or use a RegEx or whatever.
IEnumerable<string> fullMatchingKeys =
dictionary.Keys.Where(currentKey => currentKey.Contains(partialKey));
List<T> returnedValues = new List<T>();
foreach (string currentKey in fullMatchingKeys)
{
returnedValues.AddRange(dictionary[currentKey]);
}
return returnedValues;
}
编辑2 :想想看,你也可以使它更通用。使用下一个扩展方法,它可以在任何字典上工作,只要您提供comparer
来检查“部分匹配”的含义:
public static IEnumerable<TValue> PartialMatch<TKey, TValue>(
this Dictionary<TKey, IEnumerable<TValue>> dictionary,
TKey partialKey,
Func<TKey, TKey, bool> comparer)
{
// This, or use a RegEx or whatever.
IEnumerable<TKey> fullMatchingKeys =
dictionary.Keys.Where(currentKey => comparer(partialKey, currentKey));
List<TValue> returnedValues = new List<TValue>();
foreach (TKey currentKey in fullMatchingKeys)
{
returnedValues.AddRange(dictionary[currentKey]);
}
return returnedValues;
}
答案 1 :(得分:4)
您正在寻找简明的答案。如果没有花哨的文本索引(我不知道任何专门的.Net类),我认为词典仍然是你最好的选择。查询类似:
myDictionary.Where(kvp => kvp.Key.Contains("11")).SelectMany(kvp => kvp.Value);
你必须在所有键中搜索一个通用子字符串,而不需要一些非常酷的魔法(不是.Net提供的),所以LINQ在这里不应该伤害你。
答案 2 :(得分:2)
如果Dictionary使用内部哈希值,那么你运气不好,因为类似的字符串会产生不同的哈希值。我刚刚在周末用C,面试测试/家庭作业实施了这个要求的解决方案。我使用排序数组作为底层结构 - 昂贵的插入,但快速查找(使用二进制搜索)。要查找带有以前缀开头的密钥的所有条目,我会找到第1个,然后再进入下一个,下一个...对于一般子字符串,即不仅是前缀,我的解决方案不起作用。此刻我不知道为“一般子串”搜索建议什么。
答案 3 :(得分:2)
你可以有三本词典。年,月,日。
请注意,当您向三个词典添加项目时,您不会复制这些项目。
使用两个键拉出项目时,可以使用LINQ Extension方法Intersect()来获取与两个键匹配的项目(在两个结果集上使用Intersect)。
警告,这样做不会导致执行速度最快的代码。
答案 4 :(得分:1)
简洁的方法是使用多值映射。
例如:
Dictionary<string, Dictionary<string, List<int>>
为什么不将2011-07作为键存储,将15作为内部字典键,将1,2,3作为值存储。
map [“2011-07”] [“15”] = {1,2,3};
如果您只想要2011-07
,您可以通过遍历获取其他字典中的所有内容。
map["2011-07"]
//将返回你的1,2,3,4,5,6
如果你想去特定的一天,2011-07-15
,这将只返回1,2,3
foreach(var element in map["2011-07"]){
var values = element.values; // and you can append them to a list.
}
如果您需要年/月/日,则需要多级词典。或者您也可以使用树。