#c# #linq
#c# #linq
Вопрос:
У меня есть обычная операция GroupBy над перечислимым:
e.GroupBy(i => i.Property)
Но если i.Property действительно является коллекцией, как бы я разделил коллекцию и использовал элементы списка в качестве ключей группировки?
Например, допустим, у меня есть два объекта (Z, Y), у каждого из которых есть список:
Z: { List = { A, B, C }}
Y: { List = { B, C, D }}
Теперь запуск GroupBySubelement (o => o.List) не будет группироваться по самому списку, но будет выполнять итерации по списку и генерировать следующие группировки.
{A, {Z}}
{B, {Z, Y}}
{C, {Z, Y}}
{D, {Y}
Возможно ли это?
Спасибо!
Ответ №1:
Вот несколько примеров кода, который достигает желаемого:
//This is just temporary data. Has the similar structure to what you want.
var parts = new[]
{
new
{
Name = "X",
Property = new[] {'A', 'B', 'C'}
},
new
{
Name = "Y",
Property = new[] {'B', 'C', 'D'}
},
new
{
Name = "Z",
Property = new char[] { }
}
};
var groupedBySub = from part in parts
from sub in part.Property
group part by sub;
foreach(var group in groupedBySub)
{
Console.WriteLine("{0} - {1}", group.Key, string.Join(", ", group.Select(x => x.Name)));
}
Какие результаты:
A - X
B - X, Y
C - X, Y
D - Y
Вы также можете достичь этого с помощью цепочки методов:
var groupedBySub = parts.SelectMany(part => part.Property, (part, sub) => new {part, sub}).GroupBy(t => t.sub, t => t.part);
Если вы хотите записать его с пустым списком:
var groupedBySub = from part in parts
from sub in part.Property.DefaultIfEmpty()
group part by sub;
Который при замене приведенного выше кода выдает результат:
A - X
B - X, Y
C - X, Y
D - Y
- Z
Комментарии:
1. Кажется, это работает; части, которые мне не хватало, были альтернативными способами использования SelectMany и предложения DefaultIfEmpty . Спасибо.
Ответ №2:
Это сделало бы:
var combinations = e.SelectMany(i => i.List.Select(x => new { x, i }));
var groups = combinations.GroupBy(c => c.x, c => c.i);
Комментарии:
1. Будет ли это отражать случай, когда список пуст?
2. Но чего вы хотите в таком случае? Группа с нулевым ключом?
Ответ №3:
Часть проблемы здесь в том, что у вас нет хорошей структуры данных:
var z = new List<T>(); // I'm using T here, so let's pretend this is in a generic method
var y = new List<T>();
// add a bunch of stuff
На самом деле не существует никакого алгоритма, который может дать вам то, что вы хотите, потому что переменные Z и Y на самом деле неизвестны структуре данных, только компилятору.
Но что, если бы у вас была структура данных, подобная этой:
var allOfTheLists = new Dictionary<T, List<T>>();
Затем вы могли бы разбить его, используя что-то вроде этого:
var explodedList = allOfTheLists.SelectMany((pair) => pair.Value.Select((item) => new { pair.Key, item}));
var grouping = explodedList.GroupBy((explodedItem) => explodedItem.item);