是否有可能对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。

谁能推荐一个简洁的方法来实现这个目标?或者为检索这些信息提供更好的数据结构?

是否有可能对Dictionary字符串键进行部分字符串匹配

我将做一个扩展方法:

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.
}

如果你需要年/月/日,你将需要多级字典。或者您也可以使用