是否有可能对Dictionary字符串键进行部分字符串匹配
本文关键字:字符串 行部 字符 串匹配 有可能 Dictionary 是否 | 更新日期: 2023-09-27 18:11:34
我的代码中有一个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。
谁能推荐一个简洁的方法来实现这个目标?或者为检索这些信息提供更好的数据结构?
我将做一个扩展方法:
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表达式中转换它,但概念保持不变。
Edit:在您的示例中,此方法将返回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;
}
Edit 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;
}
你在寻找简洁的答案。如果没有低级别的文本索引(我不知道有什么专门的。net类),我认为字典仍然是你最好的选择。使用类似以下语句的查询:
myDictionary.Where(kvp => kvp.Key.Contains("11")).SelectMany(kvp => kvp.Value);
无论如何,您必须搜索所有键以获得广义子字符串,而没有一些非常酷的魔法(. net没有提供),因此LINQ在这里不会给您带来太大的伤害。
如果Dictionary使用内部哈希,那么您就不走运了,因为相似的字符串产生不同的哈希。我只是在周末在C中实现了这个要求的解决方案,面试测试/家庭作业。我使用了一个排序数组作为底层结构——插入代价很高,但查找速度很快(使用二进制搜索)。要找到所有以前缀开头的键项,我会找到第一个,然后只是下一个,下一个…对于一般子字符串,即不仅仅是前缀,我的解决方案将不起作用。在这一刻,我不知道什么建议为"一般子字符串"搜索。
可以有三个字典。年、月、日。
请注意,当您向三个字典中添加项时,您不是在重复这些项。
当您使用两个键拉出项目时,您可以使用LINQ扩展方法Intersect()来获取与两个键匹配的项目(在两个结果集上使用Intersect)。
注意,这样做不会产生最快的执行代码。
一种简洁的方法是使用多值映射。
例如:
Dictionary<string, Dictionary<string, List<int>>
为什么不将2011-07存储为键,将15存储为内部字典键,将1,2,3存储为值呢?
地图("2011 - 07年")("15")= {1,2,3};
如果你只想要2011-07
,你可以通过遍历获得其他字典中的所有内容。
map["2011-07"]
//将返回u 1,2,3,4,5,6
,如果你想去一个特定的日子,2011-07-15
,这将只返回u 1,2,3
foreach(var element in map["2011-07"]){
var values = element.values; // and you can append them to a list.
}
如果你需要年/月/日,你将需要多级字典。或者您也可以使用树