C#linq查询聚合可空布尔值

C#linq查询聚合可空布尔值,c#,linq,boolean,nullable,C#,Linq,Boolean,Nullable,我想使用linq按照以下逻辑聚合一个可为null的bool: 如果一切都是真的,那么就是真的 如果一切都是假的,那么就是假的 否则无效 这是我的代码,我无法获取bool聚合 class T1 { public string property1{get;set;} public string property2{get;set;} public bool? BoolProperty{get;set;} } ///initialize a list<T1> t2 wit

我想使用linq按照以下逻辑聚合一个可为null的bool:

  • 如果一切都是真的,那么就是真的
  • 如果一切都是假的,那么就是假的
  • 否则无效
这是我的代码,我无法获取bool聚合

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类
{
公共字符串属性1{get;set;}
公共字符串属性2{get;set;}
公共布尔?布尔属性{get;set;}
}
///使用值初始化列表t2。。。。。。
列表t2=新列表();
t2.添加(新的T1()
{
property1=“你好”,
property2=“世界”,
BoolProperty=true
});
t2.添加(新的T1()
{
property1=“你好”,
property2=“世界”,
BoolProperty=false
});
列表t1=t2.GroupBy(g=>new
{
g、 房地产1,
g、 物业2
})
.选择(g=>new T1
{
property1=g.Key.property1,
property2=g.Key.property2,
BoolProperty=////有人能帮忙吗?如果t2中的所有对象都为true,则为true;如果t2中的所有对象都为false,则为false;否则为null
///在这种情况下,我期望为空
}).ToList();
所以t1将是“你好”,“世界”,空;
谢谢

我建议以下解决方案。它需要使用

List t1=t2.GroupBy(g=>new
{
g、 房地产1,
g、 物业2
}).选择(groupedItems=>
{
//我的代码从这里开始
bool?结果=null;
var bools=groupedItems
.OrderBy(z=>z.BoolProperty)
.TagFirstLast((z,first,last)=>new{z,firstOrLast=first | | last})
.其中(z=>z.firstOrLast)
.Select(z=>z.z.BoolProperty).ToList();
如果(bools.Count==0)
{
//无所事事
}
else if(bools.First()==bools.Last())
{
结果=bools.First();
}
//我的代码到此结束
返回新的T1
{
property1=groupedItems.Key.property1,
property2=groupedItems.Key.property2,
BoolProperty=结果
};
}).ToList();
关键位是使用
OrderBy
,以确保
true
false
null
值相邻(即按顺序分组)

然后,
TagFirstLast
允许我们忽略除第一个和最后一个条目之外的所有内容(这是我们所需要的)

然后我们检查第一个条目和最后一个条目是否相同——如果相同,则使用该值(无论是
null
还是
true
还是
false
——无论哪种方式都符合要求)

否则,请使用
null
(因为这将是您的
else
条件)。

您可以使用

var allTrue = t2.All(x=>x.BoolProperty == true);
var allFalse = t2.All(x=>x.BoolProperty == false);
var anyNull = t2.Any(x=>x.BoolProperty.HasValue == false);
分组前。

这个怎么样

BoolProperty = g.All(p => p.BoolProperty.GetValueOrDefault())
    ? true
    : (g.All(p => !(p.BoolProperty ?? true))
        ? (bool?)false
        : null)
            }).ToList();

把这个写进你的代码里

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();
List t1=t2.GroupBy(g=>new
{
g、 房地产1,
g、 物业2
})
.选择(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();

这一切都可以由linq来完成,但这绝对不是最有效的方法,因为您需要多次枚举或使用其他sheneigan。有时最好的方法是简单的旧代码

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;
}
如果你真的想用标准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
虽然该值要么是第一个值,要么等于它的前导值,但它会不断变为forwared。因此,如果序列完全由相同的元素组成,那么它将被转发。但是,如果它不同,-2将被转发,这将始终不同于剩余的任何其他元素。
最后,第二个lambda只是将结果转换回一个
bool?

这似乎是可行的…但我不确定为什么有人在没有评论的情况下否决了它?是的,也不确定为什么否决了它!如果它对您有效,请接受!:)我在等待注释的同时做更多的测试。我看到这种方法的一个缺点是
All
必须在数据集上迭代两次。无可否认,这不是一个巨大的缺点。
p.BoolProperty.HasValue&!p、 BoolProperty.Value
可以简化为
!(p.BoolProperty??true)
p.BoolProperty.HasValue和&p.BoolProperty.Value
p.BoolProperty??false
。我希望可以选择多个答案。谢谢大家的帮助!优雅,使用更少的资源。哇,答案越来越好,如果输入列表为null,false,false,false怎么办?它将返回False,而预期的返回为null。如果我错了,请纠正我。。。。thanks@Heisenberg你错了。你为什么不试试呢。。。我正在测试函数CantFindAGoodName,它返回false。。。。
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