HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Group collections by their elements property

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
elementsgrouppropertycollectionstheir

Problem

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 orders,
        IEnumerable invoices, IEnumerable payments){...}

    public Guid CustomerId { get; set; }
    public IEnumerable Invoices { get; set; }
    public IEnumerable Orders { get; set; }
    public IEnumerable Payments { get; set; }
}


Right now I am doing so by this function:

```
private IEnumerable _GetCustomerInfo(
IEnumerable payments, IEnumerable invoices,
IEnumerable orders)
{
var invoicesGroupdByCustomers = invoices.GroupBy(x => x.CustomerId);
var ordersGroupdByCustomers = orders.GroupBy(x => x.CustomerId);
var paymentsGroupdByCustomers = payments.GroupBy(x => x.CustomerId);

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

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

Solution

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 => x.CustomerId)
.Select(g => 
          new CustomerInfo(g.Key, 
                 g.OfType(), 
                 g.OfType(),
                 g.OfType())

Code Snippets

public interface ICustomerItem
    {
        Guid CustomerId {get;}
     }
var items = invoices.Concat(payments).Concat(orders);
items
.GroupBy(x => x.CustomerId)
.Select(g => 
          new CustomerInfo(g.Key, 
                 g.OfType<Order>(), 
                 g.OfType<Payment>(),
                 g.OfType<Invoice>())

Context

StackExchange Code Review Q#18657, answer score: 6

Revisions (0)

No revisions yet.