是否可以使用 LINQ 对新对象中多个对象的值求和

Posted

技术标签:

【中文标题】是否可以使用 LINQ 对新对象中多个对象的值求和【英文标题】:Is it possible to use LINQ to sum the value of multiple objects in a new object 【发布时间】:2020-08-14 07:22:03 【问题描述】:

假设我有一个具有以下属性的对象类 MyObject

class MyObject 
   public int MyProperty1  get; set; 
   public int MyProperty2  get; set; 
   public int MyProperty3  get; set; 

我有一个 MyObject[] 数组,其中包含以下元素:

MyObject[] myObjects => new MyObject[]  myObject1, myObject2, myObject3 ;

我如何创建一个新实例 myObject 使其 MyProperty1MyProperty2MyProperty3 是数组中每个此类对象各自属性的总和?

目前我的实现如下

MyObject MyObjectSummed => new MyObject()

   MyProperty1 = myObjects.Sum(x => x.MyProperty1);
   MyProperty2 = myObjects.Sum(x => x.MyProperty2);
   MyProperty3 = myObjects.Sum(x => x.MyProperty3);

但我依稀记得看到过一种更有效的方法,即使用 LINQ,使用一行代码。

这可能吗?有人可以指出正确的方向吗?

谢谢!

【问题讨论】:

看看聚合扩展方法。 ***.com/questions/7105505/… 出于兴趣比较 Aggregate 与 foreach 性能的小示例:ideone.com/RliVVp 【参考方案1】:

您需要更新三个属性,因此“单行”会使代码非常不可读。

如果询问不同的 LINQ 方法而不是总结三个值,那么Aggregate 是您的选择,请查看@Andy 的答案。

如果你用方法包装逻辑,那么你可以在实现中使用任意数量的行,但为消费者保持单行。

替代方法可以是可枚举的扩展方法

public static MyObject CalculateSum(this IEnumerable<MyObject> objects)

    var total = new MyObject();
    foreach (var obj in objects)
    
        total.MyProperty1 += obj.MyProperty1;
        total.MyProperty2 += obj.MyProperty2;
        total.MyProperty3 += obj.MyProperty3;
    

    return total;

用法是“单线”:)

var objects = new MyObject[]  myObject1, myObject2, myObject3 ;

var sum = objects.CalculateSum();

请注意,所有 LINQ 方法都是扩展方法,因此您有点使用自己的域特定 LINQ“单线”;)

【讨论】:

【参考方案2】:

所以如果你不想改变原来的array,你可以这样做:

    var result = myObjects.Aggregate(new MyObject(), (accumulate, current) => 
           accumulate.MyProperty1 += current.MyProperty1;
           accumulate.MyProperty2 += current.MyProperty2;
           accumulate.MyProperty3 += current.MyProperty3;
           return accumulate;
    );

如果你不在乎,你可以这样做:

通过这种方式,您正在改变数组中的第一个元素。

    var result = myObjects.Aggregate((accumulate, current) => 
           accumulate.MyProperty1 += current.MyProperty1;
           accumulate.MyProperty2 += current.MyProperty2;
           accumulate.MyProperty3 += current.MyProperty3;
           return accumulate;
    );

【讨论】:

感谢更新,不用担心。 Nup,我觉得很好 :) +1 你应该提供一个初始化值myObjects.Aggregate(new MyObject(), (accumulate, current)...,你应该更新/返回accumulate,而不是current。当前的实现正在修改我怀疑是未缩进的副作用的原始值列表。 检查myObjects[1]在运行这个聚合之前和之后的属性值,它们已经改变了 这与 OP 的原始解决方案 O(n) 具有相同的效率水平,并且行数甚至比原始解决方案更多;) 这也会改变数组,这次是更新第一项。您需要提供一个初始化器值,因为您正在聚合一个对象列表(由 ref 传递)。【参考方案3】:

如果性能不是问题,您可以使用反射。然后,您可以向对象添加和删除整数属性,而无需修改添加代码。如果将GetProperties()的返回值转换为列表,可以使用List&lt;T&gt;ForEach()方法,甚至可以进一步减少行数。

MyObject myObjectSummed = new MyObject();
foreach(var prop in myObjectSummed.GetType().GetProperties().Where(p => p.PropertyType == typeof(int)))

    prop.SetValue(myObjectSummed, myObjects.Sum(x => (int)prop.GetValue(x)));

但我推荐 Fabio 的回答:从我的角度来看,这是编写此逻辑的最清晰的方法。尽可能少的代码行并不总是最好的方法。

【讨论】:

感谢您的回复。鉴于我的实际对象不仅有 3 个属性,我希望有一种方法可以聚合它们,而不必像我之前的实现那样遍历每个属性的数组。法比奥的答案似乎是最好的。

以上是关于是否可以使用 LINQ 对新对象中多个对象的值求和的主要内容,如果未能解决你的问题,请参考以下文章

选择多个字段分组并求和

Flutter:如何合并两个对象并对同一个key的值求和?

如何通过特定对象键对数组中的值求和?

使用 Linq 搜索值是不是存在于对象列表中

如何使用 linq 查询具有嵌套列表的对象?

LINQ的求和 平均 最大 最小 分组 计数 等等