[英]Merge List of identical objects into single one with bool properties C#
I'm really trying to figure it out how to do it and if its possible, but seems I'm stuck.我真的很想弄清楚如何去做,如果可能的话,但似乎我被困住了。
I have some object我有一些 object
public class Obj
{
public bool Allow { get; set;}
public bool Forbidden { get; set; }
public bool Forgotten { get; set; }
}
And I have List<Obj>
, which all of those objects in the list has to be combined in single Obj
, where if the property is true
in any of those objects should be set to true
, else keep it false
.我有List<Obj>
,列表中的所有这些对象都必须组合在单个Obj
中,如果这些对象中的任何一个属性为true
,则应将其设置为true
,否则保持为false
。
Eg例如
List<Obj> list = new List<Obj>()
{
new Obj() { Allow = false, Forbidden = false, Forgotten = true },
new Obj() { Allow = true, Forbidden = false, Forgotten = false },
new Obj() { Allow = false, Forbidden = false, Forgotten = true }
}
In that case I would get new Obj
with values Allow = true (in one of the objects its set to True), Forbidden = false, Forgotten = true (there is object with this property set to True as well)
在这种情况下,我会得到新的Obj
,其值Allow = true (in one of the objects its set to True), Forbidden = false, Forgotten = true (there is object with this property set to True as well)
Is this possible in elegant way without doing multiple .Where()
for example?例如,这是否可能以优雅的方式而不需要执行多个.Where()
?
This should work:这应该有效:
public Obj CoalesceObjs(IEnumerable<Obj> items)
{
var result = new Obj();
foreach(var item in items)
{
result.Allow = result.Allow || item.Allow;
result.Forbidden = result.Forbidden || item.Forbidden;
result.Forgotten = result.Forgotten || item.Forgotten;
if (result.Allow && result.Forbidden && result.Fogotten) return result;
}
return result;
}
If you really want to use linq, you could also do this:如果你真的想使用 linq,你也可以这样做:
var seed = new Obj();
list.Aggregate(seed, (cur, next) => {
cur.Allow = cur.Allow || next.Allow;
cur.Forbidden = cur.Forbidden || next.Forbidden;
cur.Fogotten = cur.Forgotten || next.Forgotten;
return cur;
});
//seed is now also the result
Which I could again wrap in a function like so:我可以再次将其包装在 function 中,如下所示:
public Obj CoalesceObjs(IEnumerable<Obj> items)
{
var seed = new Obj();
return list.Aggregate(seed, (cur, next) => {
cur.Allow = cur.Allow || next.Allow;
cur.Forbidden = cur.Forbidden || next.Forbidden;
cur.Fogotten = cur.Forgotten || next.Forgotten;
return cur;
});
}
Update: added an early-exit to the first option.更新:在第一个选项中添加了提前退出。
If performance doesn't matter, a really elegant and really easy to read way is like:如果性能无关紧要,那么一种非常优雅且非常易于阅读的方式就像:
Obj result = new Obj()
{
Allow = list.Any(o => o.Allow),
Forbidden = list.Any(o => o.Forbidden),
Forgotten = list.Any(o => o.Forgotten)
};
Note that you are querying your list 3 times, for a potentially more performant solution you could make use of LINQs Aggregate
.请注意,您正在查询您的列表 3 次,对于可能更高性能的解决方案,您可以使用 LINQs Aggregate
。 But it really depends where the first true
s are occuring.但这真的取决于第一个true
s 出现在哪里。
I've actually made it with reflection, because I don't want to go and add related properties if new one comes我实际上是通过反射完成的,因为我不想 go 并在新属性出现时添加相关属性
public static T MergeInSingleObjectBool<T>(this List<T> list)
where T : new()
{
var obj = new T();
foreach (var item in list)
{
var type = item.GetType();
foreach (var prop in type.GetProperties())
{
var name = prop.Name;
var value = (bool)type.GetProperty(name).GetValue(item);
if (value)
{
obj.GetType().GetProperty(name).SetValue(obj, value);
// we found true for our prop
break;
}
}
}
return obj;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.