【问题标题】:Calculating the sum of the values in a dictionary that exist in a generic list计算存在于通用列表中的字典中的值的总和
【发布时间】:2017-07-02 22:14:55
【问题描述】:

我对 LINQ 不是特别精通,所以我可以在这个特定场景中使用一些帮助。

我有一个字典项目列表。我需要对字符串列表中存在键的字典中的值求和。

如何为这样的事情编写 LINQ 表达式?

Dictionary<string, decimal> cars = new Dictionary<string, decimal>();

cars.Add("Ford", 1.2M);
cars.Add("Chevy", 2M);
cars.Add("Toyota", 3M);
cars.Add("Audi", 5M);

List<string> selectedList = new List<string>();
selectedList.Add("Chevy");
selectedList.Add("Audi");

【问题讨论】:

    标签: c# .net linq list dictionary


    【解决方案1】:

    就是这样:

    var sum = selectedList.Sum(s=>cars[s]);
    

    或者如果您不确定,所有值都在字典中(感谢 Tim Schmelter 的更正):

    var sum = selectedList.Sum(s=>cars.ContainsKey(s)?cars[s]:0);
    

    编辑: 更好的是 Tim 提出的解决方案:

    selectedList.Where(cars.ContainsKey).Sum(s => cars[s])
    

    【讨论】:

    • @TimSchmelter 我已经更新了答案,你说得对,它不是很安全。
    • 谢谢。或者你可以使用:selectedList.Where(cars.ContainsKey).Sum(s =&gt; cars[s])
    • 如果使用TryGetValue会更好
    【解决方案2】:

    您可以过滤字典中的项目,然后对值求和:

    var sum = cars
        .Where(item => selectedList.Contains(item.Key))
        .Sum(item => item.Value);
    

    【讨论】:

    • 我更喜欢 Maksim 的方法。考虑到字典包含数千辆汽车,但只选择了 1-2 辆,您总是枚举整个字典并且不会从它的查找性能中受益。
    • 这将比尝试为每个 selectedList 项目运行 ContainsKey 更有效
    • 有趣的点 Tim,但是如果 List 还包含许多条目(并且可能是重复的条目)怎么办?重复运行ContainsKey 以进行另一次查找可能会变得具有挑战性......我可能会选择TryGetValue,并且我猜在这种情况下不使用扩展。
    • @DanField:字典查找是 O(1),而列表需要 O(n),因此您应该始终使用字典进行查找。如果选定列表表明它只包含一个子集,则更是如此。此外,不要通过避免ContainsKey 进行微优化。它使代码更具可读性。 TryGetValue 需要使用局部变量(如果不是 C#7)作为 LINQ 中应避免的外变量(副作用)。
    • 足够公平@TimSchmelter,虽然我认为可以在 LINQ 中使用该局部变量就好了 - 对于建议大小的集合,这是一个微优化,但如果你正在处理更大的集合或者如果您的字典同时被访问(或者是ConcurrentDictionary),我认为我在下面发布的解决方案会更好一些...... FWIW,我赞成两个​​最佳答案,因为它们都是可行的解决方案。跨度>
    【解决方案3】:

    所以这里有一种不同的方法,它可能在某些边缘情况下表现得更好:

    var sum = selectedList
                .Distinct()
                .Sum(s =>
                {
                    decimal d;
                    if (cars.TryGetValue(s, out d))
                    {
                        return d;
                    }
                    return 0;
                }
            );
    

    您只需要迭代列表中的不同值,这样您就可以避免在cars 字典中重复查找(如果不是这种情况,则只需注释掉Distinct())。无论列表或字典是否更大,这都应该提供良好的性能平衡。

    【讨论】:

    • 更新了我的解释——.Distinct() 如果不是我们想要的行为,可以被注释掉。
    • 用C#7你不需要这样的伪linq,那么你可以使用selectedList.Sum(c =&gt; cars.TryGetValue(c, out price) ? price : 0),所以你不需要声明out-variables。
    【解决方案4】:

    替代非 LINQ 答案:

    decimal total = 0;
    foreach (var car in selectedList)
    {
        total += cars[car];
    }
    

    【讨论】:

    • 尽管这是一种替代解决方案,但 LINQ 提供了一种更简洁、更优雅的解决方案。
    • 我同意 LINQ 通常更优雅,只是想提供不同的答案
    • 这不安全,你会得到一个KeyNotFoundException,列表中有一辆不在字典中的汽车
    猜你喜欢
    • 2022-11-09
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    • 2020-07-19
    • 1970-01-01
    • 2015-01-28
    相关资源
    最近更新 更多