有优雅的方法吗?
假设我正在处理具有令人难以置信的数字属性(整数和双精度)的对象,如下所示:
Foo
-bar1 int
-bar2 int
-bar3 int
-foobar1 double
-foobar2 double
我有一个List的集合...有没有办法让它简单地对List中的所有数字属性求和并返回一个具有所有总数的单个对象Foo?
一如既往地谢谢你
答案 0 :(得分:2)
如果我正确理解了您的问题,并且您希望获得一个Foo
实例,其中每个成员是列表中存在的Foo
个实例的所有相应成员的总和,那么一种可能的(有点冗长,但直截了当,没有涉及魔法)的方法是使用linq Aggregate:
// Simplified Foo to prevent a lot of typing.
public class Foo
{
public int bar1 { get; set; }
public int bar2 { get; set; }
public double foobar1 { get; set; }
}
var myFooList = new List<Foo>
{
new Foo() { bar1 = 1, bar2 = 2, foobar1 = 20.0 },
new Foo() { bar1 = 5, bar2 = 8, foobar1 = 42.0 },
new Foo() { bar1 = 9, bar2 = 3, foobar1 = -10.0 },
};
var myFooSum = myFooList.Aggregate(new Foo(), (curSum, foo) =>
{
curSum.bar1 += foo.bar1;
curSum.bar2 += foo.bar2;
curSum.foobar1 += foo.foobar1;
return curSum;
});
Console.WriteLine("FooSum: bar1 = {0}, bar2 = {1}, bar3 = {2}", myFooSum.bar1, myFooSum.bar2, myFooSum.foobar1);
打印:
FooSum: bar1 = 15, bar2 = 13, bar3 = 52
如果我误解了,并且您想要将任意对象列表(其中一些可能包含多个数字字段)合并为单个和值,则可以使用@Simon Whitehead建议的方法:
public class Bar
{
public int baz { get; set; }
public double booz { get; set; }
public string nonNumeric { get; set; }
}
static double SumNumericalProperties(object obj)
{
if (obj == null)
return 0;
if (obj is int)
return (int)obj;
if (obj is double)
return (double)obj;
// etc for other numeric types.
var sum = 0.0;
foreach (var prop in obj.GetType().GetProperties())
{
if (typeof(int).IsAssignableFrom(prop.PropertyType))
sum += (int)prop.GetValue(obj);
else if (typeof(double).IsAssignableFrom(prop.PropertyType))
sum += (double)prop.GetValue(obj);
// etc for other numeric types.
}
return sum;
}
var myObjectList = new List<object>
{
new Foo() { bar1 = 1, bar2 = 2, foobar1 = 20.0 },
new Bar() { baz = 10, booz = 100.0 },
24,
33.3333,
new Foo() { bar1 = 5, bar2 = 8, foobar1 = 42.0 },
new Foo() { bar1 = 9, bar2 = 3, foobar1 = -10.0 },
};
var myFooSum = myObjectList.Sum(SumNumericalProperties);
Console.WriteLine("Sum = {0}", myFooSum);
打印哪些:
Sum = 247.3333
答案 1 :(得分:2)
也可以使用这种单线程来完成: - )
Item sum = (from p in typeof(Item).GetFields()
where Type.GetTypeCode(p.FieldType) == TypeCode.Int32 || Type.GetTypeCode(p.FieldType) == TypeCode.Double
group p by p into g
select new { Prop=g.Key, Sum=items.Sum(s => (decimal)Convert.ChangeType(g.Key.GetValue(s), TypeCode.Decimal)) })
.Aggregate(new Item(), (state, next) => {
next.Prop.SetValue(state, Convert.ChangeType(next.Sum, next.Prop.FieldType));
return state;
});
完整样本:
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
class Item
{
public int bar1 = 0;
public int bar2 = 0;
public double foobar1 = 0;
public double foobar2 = 0;
}
public static void Main ()
{
var items = new List<Item>();
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });
var sum = (from p in typeof(Item).GetFields()
where Type.GetTypeCode(p.FieldType) == TypeCode.Int32 || Type.GetTypeCode(p.FieldType) == TypeCode.Double
group p by p into g
select new { Prop=g.Key, Sum=items.Sum(s => (decimal)Convert.ChangeType(g.Key.GetValue(s), TypeCode.Decimal)) })
.Aggregate(new Item(), (state, next) => {
next.Prop.SetValue(state, Convert.ChangeType(next.Sum, next.Prop.FieldType));
return state;
});
Console.WriteLine("bar1: " + sum.bar1);
Console.WriteLine("bar2: " + sum.bar2);
Console.WriteLine("foobar1: " + sum.foobar1);
Console.WriteLine("foobar2: " + sum.foobar2);
}
}
答案 2 :(得分:1)
粗暴尝试:
private static double sumNumericalProperties<T>(T obj)
{
var result = 0d;
foreach (var prop in typeof (T).GetProperties())
{
if (typeof(int).IsAssignableFrom(prop.PropertyType))
{
result += (int)prop.GetValue(obj);
}
else if (typeof(double).IsAssignableFrom(prop.PropertyType))
{
result += (double) prop.GetValue(obj);
}
}
return result;
}
示例输入:
class Foo
{
public int Bar1 { get; set; }
public int Bar2 { get; set; }
public double Foobar1 { get; set; }
public double Foobar2 { get; set; }
public string BufferProperty { get; set; }
}
var obj = new Foo() {Bar1 = 2, Bar2 = 4, Foobar1 = 5, Foobar2 = 6};
var obj2 = new Foo() { Bar1 = 2, Bar2 = 4, Foobar1 = 5, Foobar2 = 7 };
var list = new List<Foo>();
list.Add(obj); // 17
list.Add(obj2); // 18
Console.WriteLine(list.Sum(x => sumNumericalProperties(x))); // 35