C#Linq查询聚合可为空的布尔值

时间:2019-03-20 21:23:05

标签: c# linq boolean nullable

我想使用linq按照以下逻辑聚合可为空的布尔值:

  • 如果全部为真,则为真;
  • 如果全部为假,则为false;
  • 其他为空

这是我的代码,我无法获取布尔值集合。

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; 谢谢

5 个答案:

答案 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,以确保truefalsenull的值是相邻的(即按顺序分组在一起)。

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

然后,我们检查第一个和最后一个条目是否相同-如果相同,则使用该值(无论是null还是truefalse-都适合要求)。

否则,请使用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>

在分组之前。