是否可以使用 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 使其 MyProperty1、MyProperty2 和 MyProperty3 是数组中每个此类对象各自属性的总和?
目前我的实现如下
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<T>
的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 对新对象中多个对象的值求和的主要内容,如果未能解决你的问题,请参考以下文章