C# 在字典上使用 LINQ Where 子句时,如何返回相同类型的字典?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/897038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 22:03:21  来源:igfitidea点击:

When using a LINQ Where clause on a Dictionary, how can I return a dictionary of the same type?

c#linqoptimization

提问by Loki

I'm currently using the following code to achieve this, but is seems there should be something better... suggestions? It just seems to me there should be a way to skip the foreach...

我目前正在使用以下代码来实现这一点,但似乎应该有更好的东西......建议?在我看来应该有一种方法可以跳过 foreach ......

Dictionary<string,string> getValidIds(Dictionary<string,string> SalesPersons,List<string> ids)
{
    Dictionary<string,string> o = new Dictionary<string,string>();
    var ie = SalesPersons.Where<KeyValuePair<string, string>>(t => ids.Contains(t.Key));
    foreach (var i in ie)
    {
        o.Add(i.Key, i.Value);
    }
    return o;
}

采纳答案by Amy B

Seems to be a lot of fussing about looking things up in the List. If the list only contains a few elements, then no big deal. If the List contains thousands of elements, you're going to want O(1) lookups into it. HashSet can provide this.

在列表中查找内容似乎很麻烦。如果列表只包含几个元素,那么没什么大不了的。如果 List 包含数千个元素,您将需要 O(1) 次查找。HashSet 可以提供这个。

Dictionary<string, string> getValidIds(
  Dictionary<string, string> SalesPersons,
  List<string> ids
)
{
  HashSet<string> idsFast = new HashSet<string>(ids);
  Dictionary<string, string> result = SalesPersons
    .Where(kvp => idsFast.Contains(kvp.Key))
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
  return result;
}

回答by Matt Hamilton

Pretty sure you could just call ToDictionary on the result of the Where call:

很确定你可以在 Where 调用的结果上调用 ToDictionary :

Dictionary<string, string> GetValidIds(Dictionary<string, string> salesPersons,
    IList<string> ids)
{
    return salesPersons
        .Where(p => ids.Contains(p.Key))
        .ToDictionary(p => p.Key, p => p.Value);
}

回答by Marc Gravell

Interestingly, if you enumerate over the dictionary (length N) firstand check the list (length M) for inclusion, then you get O(NM) performance.

有趣的是,如果枚举字典(长度N)第一和检查清单(长度M)列入,那么你得到O(NM)性能。

You could build a HashSet<>of the ids, but that seems redundant since we already have a (pre-hashed) dictionary available.

您可以构建一个HashSet<>id,但这似乎是多余的,因为我们已经有一个(预先散列的)字典可用。

I would instead iterate over the ids first; since dictionary lookup (by key) is O(1), this gives O(M) performance - this might, however, mean that you don't use LINQ (since TryGetValuewon't love LINQ (and introducing a tuple is too much like hard work)...

相反,我会先遍历 id;由于字典查找(按键)是 O(1),这提供了 O(M) 性能 - 但是,这可能意味着您不使用 LINQ(因为TryGetValue不会喜欢 LINQ(并且引入元组太像了)辛苦了)...

    Dictionary<string, string> getValidIds(
            IDictionary<string, string> salesPersons,
            IEnumerable<string> ids) {
        var result = new Dictionary<string, string>();
        string value;
        foreach (string key in ids) {
            if (salesPersons.TryGetValue(key, out value)) {
                result.Add(key, value);
            }
        }
        return result;
    }

It doesn't overly concern me that this is more lines than the LINQ version; it removes an O(N) of complexity...

我并不太担心这比 LINQ 版本的行数多;它消除了 O(N) 的复杂性......



Edit; the following mightwork (I haven't tested it), but I think it is an abuse of LINQ, and certainly won't scale to PLINQ etc... use with extreme caution!! I also believe the foreachapproach simply has fewer overheads, so will be quicker... anyway:

编辑; 以下可能有效(我还没有测试过),但我认为这是对 LINQ 的滥用,当然不会扩展到 PLINQ 等......使用时要格外小心!我也相信这种foreach方法的开销更少,所以会更快......无论如何:

    Dictionary<string, string> getValidIds(
        IDictionary<string, string> salesPersons,
        IEnumerable<string> ids)
    {
        string value = null;
        return  (from key in ids
                where salesPersons.TryGetValue(key, out value) // HACK: v. dodgy
                select new { key, value })
                .ToDictionary(x=>x.key, x=>x.value);
    }