我想使用linq按照以下逻辑聚合可为空的布尔值:
这是我的代码,我无法获取布尔值集合。
class T1
{
public string property1{get;set;}
public string property2{get;set;}
public bool? BoolProperty{get;set;}
}
///initialize a list<T1> t2 with values......
List<T1> t2 = new List<T1>();
t2.Add(new T1()
{
property1="hello",
property2="world",
BoolProperty=true
});
t2.Add(new T1()
{
property1="hello",
property2="world",
BoolProperty=false
});
List<T1> t1 = t2.GroupBy(g => new
{
g.property1,
g.property2
})
.Select(g => new T1
{
property1 = g.Key.property1,
property2 = g.Key.property2,
BoolProperty = ////can someone help? if all object in t2 are true, true; if all object in t2 are false, false; else null
///in this case i am expecting a null
}).ToList();
因此,t1将为“ hello”,“ world”,null; 谢谢
答案 0 :(得分:3)
怎么样?
BoolProperty = g.All(p => p.BoolProperty.GetValueOrDefault())
? true
: (g.All(p => !(p.BoolProperty ?? true))
? (bool?)false
: null)
}).ToList();
答案 1 :(得分:1)
我建议以下解决方案。它要求使用MoreLINQ
。
List<T1> t1 = t2.GroupBy(g => new
{
g.property1,
g.property2
}).Select(groupedItems =>
{
// My code starts here
bool? result = null;
var bools = groupedItems
.OrderBy(z => z.BoolProperty)
.TagFirstLast((z, first, last) => new { z, firstOrLast = first || last })
.Where(z => z.firstOrLast)
.Select(z => z.z.BoolProperty).ToList();
if (bools.Count == 0)
{
// Do nothing
}
else if (bools.First() == bools.Last())
{
result = bools.First();
}
// My code ends here
return new T1
{
property1 = groupedItems.Key.property1,
property2 = groupedItems.Key.property2,
BoolProperty = result
};
}).ToList();
关键是使用OrderBy
,以确保true
,false
和null
的值是相邻的(即按顺序分组在一起)。
然后TagFirstLast
允许我们忽略除第一个和最后一个条目(这就是我们所需要的)以外的所有内容。
然后,我们检查第一个和最后一个条目是否相同-如果相同,则使用该值(无论是null
还是true
或false
-都适合要求)。
否则,请使用null
(因为这将是您的else
条件)。
答案 2 :(得分:1)
将此代码放入您的代码中,
List<T1> t1 = t2.GroupBy(g => new
{
g.property1,
g.property2
})
.Select(g => new T1
{
property1 = g.Key.property1,
property2 = g.Key.property2,
BoolProperty = g.GroupBy(grp => grp.BoolProperty).Count() > 1 ? null : g.Select(g_val=>g_val.BoolProperty).First()
}).ToList();
答案 3 :(得分:1)
这一切都可以由linq完成,但这可能永远不是最有效的方法,因为您需要枚举不止一次,或者需要其他枚举。有时最好的方法是简单的旧代码。
public static bool? CantFindAgoodName(IEnumerable<bool?> items)
{
bool? check = null;
bool first = true;
foreach(var item in items)
{
if(first)
{
check = item;
first = false;
}
else if(check != item)
return null;
}
return check;
}
然后只写
BoolProperty = CantFindAGoodName(g)
如果您真的想使用标准的Linq进行此操作,则可以通过一次迭代来完成,但是它既没有效率(因为它不会立即中断),也没有很好的表现。
BoolProperty = g.Aggregate(-1,
(n, b) => n == -1
? (b == null ? 0 : (b.Value ? 1 : 2))
: (n == (b == null ? 0 : (b.Value ? 1 : 2)) ? n : -2),
i => i == -2 ? default(bool?) : i == 1);
那么它如何工作?
-1 = seed
0 = null
1 = true
2 = false
-2 = different values aka null
尽管该值是第一个或等于其前任值,但它会不断被重视。因此,如果序列仅由同一元素组成,那么它将被转发。但是,如果其不同,则将转发-2,这将始终与剩余的任何其他元素不同。
最后,第二个lambda只是将结果转换回bool?
答案 4 :(得分:0)
您可以使用
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element">
<mat-chip-list class="no-wrap" *ngFor="let n of element.name.split(',')">
<span class="nobreak">
<mat-chip class="no-wrap">{{n}}</mat-chip>
</span>
</mat-chip-list>
</td>
</ng-container>
在分组之前。