Reputation: 13
Assuming I have an object class MyObject with the following properties:
class MyObject {
public int MyProperty1 { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
}
And I have an array of MyObject[] with the following elements:
MyObject[] myObjects => new MyObject[] { myObject1, myObject2, myObject3 };
How do I create a new instance myObject such that its MyProperty1, MyProperty2, and MyProperty3 are the sums of the respective properties for every such object in the array?
Currently, my implementation is as follows
MyObject MyObjectSummed => new MyObject()
{
MyProperty1 = myObjects.Sum(x => x.MyProperty1);
MyProperty2 = myObjects.Sum(x => x.MyProperty2);
MyProperty3 = myObjects.Sum(x => x.MyProperty3);
}
but I vaguely remember seeing a more efficient way of doing this using LINQ, using a single line of code.
Is this possible and can someone please point me in the right direction?
Thanks!
Upvotes: 1
Views: 996
Reputation: 4684
So if you do not want to mutate the original array
, this is what you can do:
var result = myObjects.Aggregate(new MyObject(), (accumulate, current) => {
accumulate.MyProperty1 += current.MyProperty1;
accumulate.MyProperty2 += current.MyProperty2;
accumulate.MyProperty3 += current.MyProperty3;
return accumulate;
});
If you do not care you can just do this:
By doing this way you are mutating the first element within the array.
var result = myObjects.Aggregate((accumulate, current) => {
accumulate.MyProperty1 += current.MyProperty1;
accumulate.MyProperty2 += current.MyProperty2;
accumulate.MyProperty3 += current.MyProperty3;
return accumulate;
});
Upvotes: 1
Reputation: 8743
If performance is not an issue, you can use reflections. Then you can add and remove integer properties to your object without having to modify the code of adding. If you convert the return value of GetProperties()
to a list, you can use the ForEach()
method of List<T>
, which even reduces your line count further.
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)));
}
But i recommend Fabio's answer: From my point of view, it's clearest way to write this logic. Having as few lines of code as possible is not always the best approach.
Upvotes: 0
Reputation: 32445
You need to update three properties, so having "one-liner" will make code very unreadable.
If asking about different LINQ approach instead of summarising three values, then Aggregate
is your choice, check @Andy's answer.
If you wrap logic with the method then you can use any amount of lines inside the implementation, but keep it one-liner for the consumers.
Alternative approach can be an extension method for enumerable
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;
}
Usage is "one-liner" :)
var objects = new MyObject[] { myObject1, myObject2, myObject3 };
var sum = objects.CalculateSum();
Notice that all LINQ methods are extension methods, so you kinda using your own domain specific LINQ "one-liner" ;)
Upvotes: 2