Group collections by their elements property I have a Customer class:

public class Customer
{
    public Guid Id { get; set; }
    // Some other properties...}


And three transactions classes that have a reference to Customer: 

public class Order
{
    public Guid CustomerId { get; set; }
    // Some other properties...}

public class Invoice
{
    public Guid CustomerId { get; set; }
    // Some other properties...}

public class Payment
{
    public Guid CustomerId { get; set; }
    // Some other properties...}


I have a collection for each of transaction type. And I want to get this collection to be "grouped" by their elements CustomerId properties. So, as a result I'd like to get a collection of such objects:

public class CustomerInfo
{
    public CustomerInfo(Guid customerId, IEnumerable&lt;Order&gt; orders,
        IEnumerable&lt;Invoice&gt; invoices, IEnumerable&lt;Payment&gt; payments){...}

    public Guid CustomerId { get; set; }
    public IEnumerable&lt;Invoice&gt; Invoices { get; set; }
    public IEnumerable&lt;Order&gt; Orders { get; set; }
    public IEnumerable&lt;Payment&gt; Payments { get; set; }
}


Right now I am doing so by this function:

private IEnumerable&lt;CustomerInfo&gt; _GetCustomerInfo(
    IEnumerable&lt;Payment&gt; payments, IEnumerable&lt;Invoice&gt; invoices,
    IEnumerable&lt;Order&gt; orders)
{
    var invoicesGroupdByCustomers = invoices.GroupBy(x =&gt; x.CustomerId);
    var ordersGroupdByCustomers = orders.GroupBy(x =&gt; x.CustomerId);
    var paymentsGroupdByCustomers = payments.GroupBy(x =&gt; x.CustomerId);

    var result = new List&lt;CustomerInfo&gt;();
    foreach (var group in invoicesGroupdByCustomers)
        result.Add(new CustomerInfo(group.Key, 
            ordersGroupdByCustomers.FirstOrDefault(x =&gt; x.Key == group.Key), 
            group,
            paymentsGroupdByCustomers.FirstOrDefault(x =&gt; x.Key == group.Key)));

    foreach (var group in ordersGroupdByCustomers)
        if (!result.Any(x =&gt; x.CustomerId == group.Key))
            result.Add(new CustomerInfo(group.Key, 
                group,
                invoicesGroupdByCustomers.FirstOrDefault(x =&gt; x.Key == group.Key),
                paymentsGroupdByCustomers.FirstOrDefault(x =&gt; x.Key == group.Key)));

    foreach (var group in paymentsGroupdByCustomers)
        if (!result.Any(x =&gt; x.CustomerId == group.Key))
            result.Add(new CustomerInfo(group.Key,
                ordersGroupdByCustomers.FirstOrDefault(x =&gt; x.Key == group.Key),
                invoicesGroupdByCustomers.FirstOrDefault(x =&gt; x.Key == group.Key),
                group));

    return result;
}


Here is sample of calculations where I use these transactions collections:

private Dictionary&lt;Guid, decimal&gt; _CalculateSales(
    IEnumerable&lt;CustomerInfo&gt; customersSalesInfo)
{
    var result = new Dictionary&lt;Guid, decimal&gt;();

    foreach (var customerInfo in customersSalesInfo)
    {
        var sales = customerInfo.Invoices.Sum(x =&gt; x.Header.SubTotalAmt) +
            customerInfo.Orders.Sum(x =&gt; x.Header.SubTotalAmt) -
            customerInfo.Payments.Sum(x =&gt; x.Header.SubTotalAmt);
        result.Add(customerInfo.CustomerId, sales);
    }

    return result;
}


Is there a better approach?
If they all implemented a common interface then you could simplify it.

 public interface ICustomerItem
    {
        Guid CustomerId {get;}
     }


Concat the the items together

var items = invoices.Concat(payments).Concat(orders);


Then project them into your class

 items
.GroupBy(x =&gt; x.CustomerId)
.Select(g =&gt; 
          new CustomerInfo(g.Key, 
                 g.OfType&lt;Order&gt;(), 
                 g.OfType&lt;Payment&gt;(),
                 g.OfType&lt;Invoice&gt;())