2009-06-29 1 views
0

У меня есть следующие объекты:Как я могу получить отдельные элементы следующей структуры данных в C#/LINQ?

public class Agency 
{ 
    public int ID; 
    public IEnumerable<BusinessUnit> BusinessUnits; 
} 

public class BusinessUnit 
{ 
    public int ID; 
    public decimal AmountSpent; 
    public IEnumerable<Client> Clients; 
} 

public class Client 
{ 
    public int ID; 
    public decimal AmountSpent; 
} 

Теперь у меня есть IEnumerable <Agency>, который содержит несколько агентств, эти агентства содержат несколько BusinessUnits, и те BusinessUnits содержат несколько клиентов.

Это может выглядеть примерно так:

Агентства1
++ BusinessUnit1 - $ 20
++++ Client1 - $ 10
++++ Client2 - $ 10

Agency2
+ + BusinessUnit2 - $ 20
++++ Client1 - $ 20

Агентство 3
++ BusinessUnit1 - $ 10
++++ Client5 - $ 5
++++ Client6 - $ 5
++ BusinessUnit2 - $ 25
++++ Client1 - $ 25

Теперь, что я хочу сделать, это создать список BusinessUnits и клиентов, но для всех агентств, без дубликатов.

Итак, я ищу, чтобы превратить этот список агентств в:

Все агентства
++ BusinessUnit1 - $ 30
++++ Client1 - $ 10
++++ Client2 - $ 10
++++ Client5 - $ 5
++++ Client6 - $ 5

++ BusinessUnit2 - $ 45
++++ Client1 - $ 20
++++ Client1 - $ 25

Где я просто список уникальных BusinessUnits (с правильной их общей AmountSpent во всех случаях этого конкретного BusinessUnit), а также со списком уникальных клиентов под ними, с точная сумма TotalSpent для каждого экземпляра этого конкретного клиента в рамках этой бизнес-единицы.

Возможно ли с LINQ, что я могу запросить мой список IEnumerable <Agency> Список агентов, чтобы возвращать мой отличный список комбинаций BusinessUnit/Client с правильными суммами?

+0

@Alan, правильный. Агентство.BusinessUnits имеет только один из каждого BusinessUnitID – KingNestor

+0

@Alan, однако у вас может быть Client1 в двух разных местах среди 2 разных BusinessUnits. – KingNestor

ответ

2

Нечто подобное, мне кажется (непроверенные):

var res = agencies.SelectMany(a => a.BusinessUnits) 
        .GroupBy(b => b.ID) 
        .Select(b => new BusinessUnit { 
        ID = b.Key, 
        AmountSpent = c.Sum(b2 => b2.AmountSpent), 
        Clients = b.SelectMany(b2 => b2.Clients) 
           .GroupBy(c => c.ID) 
           .Select(c => new Client { 
            ID = c.Key, 
            AmountSpent = c.Sum(c2 => c2.AmountSpent) 
           }) 
        }); 

Там может быть способ оптимизации прочь создание анонимного класса. Я оставлю это до вас. Предполагая, что BusinessUnit.AmountSpent верен, нам, вероятно, не нужно подводить итог средства AmountSpent клиента.


На второй прочитал это выглядит, как вы не можете свернуть клиентов под бизнес единиц, но сохранить каждый экземпляр, в этом случае вы можете избавиться от b.SelectMany (b2 => b2.Clients) и все что следует и просто используйте b.Clients.

1
var groupings = 
    from agency in agencies 
    from businessUnit in agency.BusinessUnits 
    from client in businessUnit.Clients 
    group client by businessUnit.ID into clients 
    select clients; 

var businessUnits = 
    from grouping in groupings 
    select new 
    { 
     ID = grouping.Key, 
     AmountSpent = grouping.Sum(client => client.AmountSpent), 
     Clients = grouping 
    }; 

Console.WriteLine("All Agencies"); 

foreach (var businessUnit in businessUnits) 
{ 
    Console.WriteLine("++BusinessUnit{0} - ${1}", 
         businessUnit.ID, 
         businessUnit.AmountSpent); 

    foreach (var client in businessUnit.Clients) 
    { 
     Console.WriteLine("++++Client{0} - ${1}", client.ID, client.AmountSpent); 
    } 
} 
+0

@ Joe Chung, очень приятно! Если BusinessUnit имеет свойство «Имя», как бы включить это в результат? Здесь я вижу, что вы обращаетесь к «ключу», но поскольку вы можете сделать это только для одного, как это изменится, если вам также понадобится строка под названием «Имя» из BusinessUnit и Client? – KingNestor

+1

В этом случае вы можете создать новый составной ключ: групповой клиент с помощью новых {businessUnit.ID, businessUnit.Name} в клиентов – Talljoe