Создать словарь в списке с группировкой

106

У меня есть следующий объект в списке:

public class DemoClass
{
    public int GroupKey { get; set; }
    public string DemoString { get; set; }
    public object SomeOtherProperty { get; set; }
}

Теперь я хочу создать из него следующий словарь:

Dictionary<int, List<DemoClass>>

Я хочу сгруппировать List<DemoClass>объекты по собственности GroupKey, но не понимаю, как это делается, и не могу помочь.

Немного подумав, я добился нужного поведения с помощью:

var groupedDemoClasses = from demoClass in mySepcialVariableWhichIsAListOfDemoClass
                            group demoClass by demoClass.GroupKey
                            into groupedDemoClass
                            select groupedDemoClass;
var neededDictionary = groupedDemoClass.ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());

но есть ли способ сделать это в одном выражении?

Андреас Нидермайр
источник

Ответы:

88
var groupedDemoClasses = (from demoClass in mySepcialVariableWhichIsAListOfDemoClass
                          group demoClass by demoClass.GroupKey
                          into groupedDemoClass
                          select groupedDemoClass).ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());

Этот будет работать !!!

Прашант Чолачагудда
источник
198

Просто чтобы конкретизировать предложение Маквандера :

var groupedDemoClasses = mySpecialVariableWhichIsAListOfDemoClass
                             .GroupBy(x => x.GroupKey)
                             .ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());

Вы бы сделали его короче, если бы использовали более короткие имена переменных, конечно :)

Однако могу ли я предположить, что поиск может быть более подходящим? Поиск - это в основном словарь от ключа до ключа IEnumerable<T>- если вам действительно не нужны значения в виде списка, он делает код еще короче (и более эффективным) с помощью вызова ToLookup :

var groupedDemoClasses = mySpecialVariableWhichIsAListOfDemoClass
                             .ToLookup(x => x.GroupKey);
Джон Скит
источник
1
Я думал, что поиск работает не так хорошо, по сравнению со встроенным словарем, в долгосрочной среде, потому что он создает свежий результат для каждого запроса ... пожалуйста, поправьте меня, если я ошибаюсь!
Андреас Нидермайр
Нет, он создает весь поиск. Как правило, ToXXX не использует отложенное выполнение.
Джон Скит
1
(Возможно, вы думаете о группировке, которая действительно отложена.)
Джон Скит,
1
Если бы я не был таким злобным, я бы проголосовал за тебя. Пришел за Linq, остался за структурой данных, о которой я никогда не слышал!
Крис Макколл,
2
@sasikt: Модель состоит в том, что вы можете искать что угодно , и вы просто получаете пустую коллекцию, если ключ не существует. Это часто более полезно, чем подход TryGetValue, IMO.
Джон Скит
6

Вы уже сделали его однострочным. Просто поставьте ToDictionaryв конце вашей первой строки. Если вы хотите, чтобы он был короче, используйте синтаксис функциональной композиции вместо синтаксиса запроса.

mqp
источник
3

Я немного отклоняюсь от темы здесь, но я попал в эту ветку, потому что искал способ создать словарь словаря в Linq, и разговор здесь привел меня к ответу ...

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

  Dim qry = (From acs In ActualSales _
             Group By acs.ProductID Into Group _
             Select ProductID, Months = Group.ToDictionary(Function(c) c.Period) _
            ).ToDictionary(Function(c) c.ProductID)

Полученный запрос можно использовать следующим образом:

 If qry.ContainsKey(_ProductID) Then
      With qry(_ProductID)
          If .Months.ContainsKey(_Period) Then
             ...
          End If
      End With
 End If

Надеюсь, это будет полезно для всех, кому нужен такой запрос.

отметка
источник