2014-12-18 2 views
1

У меня проблема, когда данный элемент может иметь более одного ключа, и мне нужно появляться в обеих коллекциях в группах. Это возможно?Можно ли группировать коллекцию, когда каждый элемент может иметь более одного ключа?

Элементы могут выглядеть как этот

class Item 
{ 
    Category mainCat {get;set;} 

    IEnumerable<Category> RelatedCategories {get;set;} 

    String RefNumber {get;set;} 
} 

class Category 
{ 
    String CatName {get;set;} 
} 

мне нужно сгруппировать набор элементов по категориям, но если элемент имеет соответствующую категорию, она должна появиться в группе для соответствующей категории и ,

Таким образом, в качестве простейшего примера я хотел бы иметь следующий экземпляр элемента в коллекции:

Ref: A1 Категория: Cat_01 RelatedCategories: {Cat_02}

Мой желаемый результат после того, как группировка будет :

Ключ: Cat_01, товары {A1} Ключ: Cat_02, товары {A1}

возможно ли это каким-либо образом?

+0

Возьмите список, чтобы добавить все связанные категории в качестве новых элементов, а затем группу. – Hogan

ответ

1

Да, вы можете сделать это следующим образом.

var dictionary = item.RelatedCategories 
    .Concat(Enumerable.Repeat(item.mainCat, 1)) 
    .ToDictionary(c => c.CatName, c => item); 

Это позволит получить соответствующие категории и сцепить основные один и использовать ToDictionary связать каждое имя категории к данному пункту.

Если вы имеете дело со списком предметов, это становится более сложным, потому что я предполагаю, что вам нужен Dictionary<string, List<Item>> в этом случае.

var dictionary = items.SelectMany(i => i.RelatedCategories 
             .Concat(Enumerable.Repeat(i.mainCat, 1)) 
             .Select(c => new { c.CatName, Item = i})) 
         .GroupBy(a => a.CatName) 
         .ToDictionary(a => a.Key, a => a.ToList()); 

Здесь внутренний запрос создает перечисление анонимных классов, которые связывают имя каждой категории с элементом. SelectMany сгладит перечисления в один. Затем GroupBy сгруппирует эти анонимные классы в группы на основе названия категории. Затем ToDictionary создаст словарь, в котором ключ является ключом каждой группы (название категории), а значение представляет собой список элементов, связанных с именем категории.

+0

О, никогда не думал об использовании 'Enumerable.Repeat' для преобразования одного объекта в перечисление. Хороший трюк! –

+0

Изумительный.Работала именно так, как мне было нужно. благодаря – CurlyPaul

1

У вас есть список Item ссылок, и вы хотите найти словарь, содержащий ключи (категории) и связанные с ними Item экземпляры. Код ниже сделает это.

var dict = new Dictionary<Category, List<Item>>(); 
foreach (var item in ItemsList) 
{ 
    AddToCategory(item, item.mainCat); 
    foreach (var cat in item.RelatedCategories) 
    { 
     AddToCategory(item, cat); 
    } 
} 

void AddToCategory(Item item, Category cat) 
{ 
    List<Item> categoryItems; 
    if (!dict.TryGetValue(cat, out categoryItems)) 
    { 
     categoryItems = new List<Item>(); 
     dict.Add(cat, categoryItems); 
    } 
    categoryItems.Add(item); 
} 

Я не вижу способ сделать это с помощью простого выражения LINQ, хотя это вполне возможно, есть способ.

+0

Вам не нужно передавать словарь в метод 'AddToCategory', или вы считаете его глобальным. – juharr

+0

@juharr: Здесь я предполагаю, что это глобально. В противном случае, да, вам придется пройти его. –

1

Это возможно с помощью запроса LINQ:

var query = from item in source 
      from category in item.RelatedCategories.Concat(new[] { item.MainCat }) 
      group item by category.CatName into g 
      select g; 

Хотя это один из немногих случаев, когда с помощью LINQ, вероятно, является не самым читаемым решением.

Смежные вопросы