LINQ中父子关联的扁平化计数

5

我想要统计没有孩子的父母和有孩子的父母数量。当我写下这句话时,我意识到最好用代码来解释。所以,接下来是代码:

假设有以下的类型:

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public string Description { get; set; }
}

And this data:

var customers = new List<Customer>
{
    new Customer
    {
        Id = 2,
        Name = "Jane Doe"
    },
    new Customer
    {
        Id = 1,
        Name = "John Doe",
        Orders = new List<Order>
        {
            new Order { Id = 342, Description = "Ordered a ball" },
            new Order { Id = 345, Description = "Ordered a bat" }
        }
    }
};

// I'm trying to get a count of customer orders added with customers with no orders
// In the above data, I would expect a count of 3 as detailed below
//
// CId      Name        OId
// ----     --------    ----
//  2       Jane Doe
//  1       John Doe    342
//  1       John Doe    345

int customerAndOrdersCount = {linq call here}; // equals 3

我正在尝试获取3的计数。谢谢你提前帮助。-Jessy Houle 补充说明:我真的对所有出色的(和快速的)答案印象深刻。对于其他来到这个问题的人,寻找一些选择,这里有一个单元测试,其中包含下面几个可行的示例。
[TestMethod]
public void TestSolutions()
{
    var customers = GetCustomers(); // data from above

    var count1 = customers.Select(customer => customer.Orders).Sum(orders => (orders != null) ? orders.Count() : 1);
    var count2 = (from c in customers from o in (c.Orders ?? Enumerable.Empty<Order>() ).DefaultIfEmpty() select c).Count();
    var count3 = customers.Sum(c => c.Orders == null ? 1 : c.Orders.Count());
    var count4 = customers.Sum(c => c.Orders==null ? 1 : Math.Max(1, c.Orders.Count()));


    Assert.AreEqual(3, count1);
    Assert.AreEqual(3, count2);
    Assert.AreEqual(3, count3);
    Assert.AreEqual(3, count4);
}

再次感谢大家的帮助!


1
提供有用的示例代码将获得+1。 - sloth
6个回答

5

你能行吗?

int customerAndOrdersCount = customers.Sum(c => c.Orders==null ? 1 : Math.Max(1, c.Orders.Count()));

1
也许我错过了问题的一部分,但为什么要使用 Math.Max 函数? - Tim Schmelter
我认为我可以自己回答我的问题:因为Orders.Count()可能为0,但应该计为1(因为所有客户都应该被计算)。+1 - Tim Schmelter
在我们的行业中,市场反应速度非常重要。感谢您的快速回复。 - Jessy Houle
有没有关于如何在NHibernate LINQ to SQL中执行此操作的想法,其中上面的内容是IQueryable<Customer>? - Jessy Houle

1
如果您将Order属性初始化为一个空列表而不是null,可以这样做:
int count =
  (
    from c in customers
    from o in c.Orders.DefaultIfEmpty()
    select c
  ).Count();

如果您决定保留未初始化的属性,则应该这样做:
int count =
  (
    from c in customers
    from o in (c.Orders ?? Enumerable.Empty<Order>() ).DefaultIfEmpty()
    select c
  ).Count();

1
customers
    .Select(customer => customer.Order)
    .Sum(orders => (orders != null) ? orders.Count() : 1)

1

如果您想将“无订单”视为1并计算其他订单,则可以使用此方法:

int customerOrders = customers.Sum(c => c.Orders == null ? 1 : c.Orders.Count());

顺便说一下,这个问题非常典型。


0

你可能正在寻找类似这样的内容:

 customers.GroupBy(customer=>customer).  //group by object iyself
        Select(c=>                       //select
                    new  
                    {
                      ID = c.Key.Id,                             
                      Name = c.Key.Name, 
                      Count = (c.Key.Orders!=null)? c.Key.Orders.Count():0
                    }
               );

0
var orderFreeCustomers = customers.Where(c=>c.Orders== null || c.Orders.Any()==false);

var totalOrders = customers.Where (c => c.Orders !=null).
Aggregate (0,(v,e)=>(v+e.Orders.Count)  );

结果是这两个值的总和


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接