Преобразовать список <MyObject> в словарь <obj.string, List <obj.ID>

Я хотел бы взять список объектов и преобразовать их в словарь, где ключ является полем в объекте, а значение представляет собой список другого поля в объектах, которые соответствуют ключу. Я могу сделать это сейчас с помощью цикла, но я считаю, что это должно быть выполнено с помощью linq и не нужно писать цикл. Я думал о комбинации GroupBy и ToDictionary, но пока не увенчался успехом.

Вот как я делаю это прямо сейчас:

var samplesWithSpecificResult = new Dictionary<string, List<int>>();
foreach(var sample in sampleList)
{
    List<int> sampleIDs = null;
    if (samplesWithSpecificResult.TryGetValue(sample.ResultString, out sampleIDs))
    {
        sampleIDs.Add(sample.ID);
        continue;
    }
    sampleIDs = new List<int>();
    sampleIDs.Add(sample.ID);
    samplesWithSpecificResult.Add(sample.ResultString, sampleIDs);
}

Самый дальний я могу получить с .GroupBy().ToDictionay() - Dictionary<sample.ResultString, List<sample>>.

Любая помощь будет оценена.

Ответы

Ответ 1

Попробуйте выполнить

var dictionary = sampleList
    .GroupBy(x => x.ResultString, x => x.ID)
    .ToDictionary(x => x.Key, x => x.ToList());

Предложение GroupBy будет группировать каждый экземпляр Sample в списке его членом ResultString, но будет содержать только часть Id каждого образца. Это означает, что каждый элемент будет IGrouping<string, int>.

В разделе ToDictionary используется Key IGrouping<string, int> в качестве словарного ключа. IGrouping<string, int> реализует IEnumerable<int>, и поэтому мы можем преобразовать эту коллекцию образцов Id в List<int> с вызовом ToList, который становится Value словаря для данного Key.

Ответ 2

Dictionary<string, List<int>> resultDictionary = 
(
  from sample in sampleList
  group sample.ID by sample.ResultString
).ToDictionary(g => g.Key, g => g.ToList());

Возможно, вы захотите использовать Lookup вместо Dictionary of Lists

ILookup<string, int> idLookup = sampleList.ToLookup(
  sample => sample.ResultString,
  sample => sample.ID
);

используется таким образом

foreach(IGrouping<string, int> group in idLookup)
{
  string resultString = group.Key;
  List<int> ids = group.ToList();
  //do something with them.
}

//and

List<int> ids = idLookup[resultString].ToList();

Ответ 3

Да, супер просто. Ключ в том, что когда вы выполняете GroupBy on IEnumerable<T>, каждая "группа" - это объект, который также реализует IEnumerable<T> (вот почему я могу сказать g.Select ниже), и я проектирую элементы оригинальная последовательность с общим ключом):

var dictionary =
     sampleList.GroupBy(x => x.ResultString)
               .ToDictionary(
                   g => g.Key,
                   g => g.Select(x => x.ID).ToList()
     );

См., результат sampleList.GroupBy(x => x.ResultString) - это IEnumerable<IGrouping<string, Sample>> и IGrouping<T, U> реализует IEnumerable<U>, так что каждая группа является последовательностью Sample с общим ключом!

Ответ 4

var samplesWithSpecificResult =
    sampleList.GroupBy(s => s.ResultString)
              .ToDictionary(g => g.Key, g => g.Select(s => s.ID).ToList());

Что мы делаем здесь, это группировать образцы на основе их ResultString - это помещает их в IGrouping<string, Sample>. Затем мы проецируем коллекцию IGrouping в словарь, используя Key каждого в качестве словарного ключа и перечисляя по каждой группе (IGrouping<string, Sample> также IEnumerable<Sample>), чтобы выбрать ID каждого образца, чтобы введите список значений словаря.