【问题标题】:Testing if a value is contained within a Dictionary<TKey, List<TValue>>测试一个值是否包含在 Dictionary<TKey, List<TValue>>
【发布时间】:2010-12-31 11:38:27
【问题描述】:

我需要确定Dictionary 中包含的任何Lists 是否包含指定值。我是 LINQ 新手,那么以下是实现此目的的正确方法吗?

Dictionary lotsOfStuff = new Dictionary<string, List<string>>();
string searchString;

// populate lotsOfStuff and searchString...

// detemine if any of the values of lotsOfStuff contain searchString
bool existsInDictionary = lotsOfStuff.Values.Any(values => values.Contains(searchString));

如果上述方法可行,有什么方法可以使它更正确或更优化/简洁?

【问题讨论】:

    标签: c# linq .net-3.5 linq-to-entities


    【解决方案1】:

    此代码有效,并且尽可能高效。因为您正在搜索值,所以没有索引/哈希来指导搜索。因此,您必须搜索所有对象以确定该值是否存在。

    【讨论】:

    • @Robert,在这种情况下不是因为用户正在搜索值中的值,而不是值本身
    • 如果您不想遍历整个字典来找出答案,应该使用什么结构?索引值的字典的一些变体?
    • @Robert,任何提供非线性搜索功能的结构。比如平衡二叉树、哈希表、排序列表等……
    【解决方案2】:

    您的代码可以运行,但有两件事立即浮现在脑海。首先是如果字典很大或值列表很大,它会很慢。想到的第二件事是你试图进行这个搜索的事实告诉我你已经把字典放在一起了。如果你有字典:

    "Frob" --> "Foo", "Bar", "Baz"
    "Blob" --> "Baz", "ABC"
    

    您要问的问题是“ABC 在任何值列表中吗?”那么你已经反向构建了字典。您要构建的字典是

    "Foo" --> "Frob"
    "Bar" --> "Frob"
    "Baz" --> "Frob", "Blob"
    "ABC" --> "Blob"
    

    您应该问的问题是“ABC 是字典的键吗?”你为什么要构建字典backwards

    【讨论】:

    • 我正在目录树中搜索存储过程名称。在这种情况下,Dictionary 的键是文件的路径名,而值是在该文件中找到的所有 proc 名称的 List(因为可变数量的存储 proc 可以包含在单个文件中) .在稍后阶段,我需要生成包含此信息的报告,但在此之前,我必须确定 Dictionary 中是否存在具有某些名称的过程。我使用的方法似乎是实现所需内容的最简单方法,但如果您有任何其他建议,我很高兴听到他们的建议!
    • 然后我会构建两个字典,一个映射目录-->过程名称列表,一个映射过程名称-->目录列表。这会使用两倍的内存,但搜索速度会快得多。
    【解决方案3】:

    该代码存在潜在问题。如果其中一个列表是null(即使该值存在于另一个列表中),您可能会得到一个NullReferenceException。要修复,请尝试:

    bool existsInDictionary = lotsOfStuff.Values
                 .Any(values => values != null && values.Contains(searchString));
    

    【讨论】:

      【解决方案4】:

      假设您想要区分大小写的匹配,您的代码将起作用,并且是最好的方法。

      如果您想要不区分大小写的匹配,请传递StringComparer,如下所示:

      lotsOfStuff.Values.Any(values => values.Contains(searchString, StringComparer.OrdinalIgnoreCase));
      

      顺便说一句,如果你想得到所有的值,你可以写

      var allValues = lotsOfStuff.Values.SelectMany(v => v);
      

      【讨论】:

        【解决方案5】:

        你的 linq 很好,我会这样做

        bool existsInDictionary = lotsOfStuff
          .SelectMany(kvp => kvp.Value)
          .Any(valString => valString == searchString);
        

        Eric Lippert 提出了一个很好的建议。如果这种搜索频繁发生,您希望使用不同的数据结构 - 具体来说,在此字典的值上散列一些东西。以下是我将如何制作和使用它。

        ILookup<string, string> reverseLookup =
        (
          from kvp in lotsOfStuff
          from valString in kvp.Value
          select new {key = valString, value = kvp.Key}
        ).ToLookup(x => x.key, x => x.value);
        
        bool existsInDictionary = reverseLookup[searchString].Any();
        

        【讨论】:

          猜你喜欢
          • 2016-06-14
          • 2011-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-09
          • 1970-01-01
          相关资源
          最近更新 更多