Как объединить n List<Dictionary<string, string>> в словарь с помощью Linq

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

Ну, это моя структура:

У меня есть запрос, который возвращает объекты списка, подобные этому:

public class MyDto 
{
  public Dictionary<string, string> JsonDictionary { get; set; }
  public Guid SomeId1{ get; set; }
  public Guid SomeId2{ get; set; } 
}

используя linq, я делаю это:

var q = _uow.TableWithJson.GetAll()
         .Include(a=> a.TableId1)
         .Include(a=> a.TableAux)
             .ThenInclude(b=> b.TableId2)
         .Select(r => new MyDto
             {
                SomeId1 = r.tableId1.Id,
                SomeId2 = r.tableId2.Id,
                JsonDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(r.JsonContent)
             });

В конце концов, у меня есть такой результат;

{
  SomeId1: xxxxx,
  SomeId2: yyyyy,
  JsonDictionary: [
    {key: key1, value: value 1}
    {key: key1, value: value 2}
    {key: key1, value: value 3}
    {key: key1, value: value 4}
  ],
},
{
  SomeId1: xxxxx,
  SomeId2: yyyyy,
  JsonDictionary: [
    {key: key4, value: value 4}
    {key: key5, value: value 5}
    {key: key6, value: value 6}
  ],
}, // many other objects with different ids and different dictionaries.

Как видите, в приведенном выше фрагменте SomeId1 и SomeId2 обоих объектов совпадают. Итак, в этом случае я хотел бы сгруппировать эти объекты, объединив поле JsonContent, в один словарь.

Также пытался использовать .GroupBy, но мне не удалось объединить этот jsonContent как агрегацию.

Помощь!!! Пожалуйста! =) Объятия

Вы пробовали Enumerable.Zip docs.microsoft.com/en-us/dotnet/api/…

Soufiane Tahiri 20.02.2019 18:01

Возможно, вы сможете сделать что-то подобное, переопределив HashSet и определив свой someid как ключ, который указывает дублирование, но возвращает false только тогда, когда оба ключа и содержимое одинаковы, иначе просто добавьте содержимое...

swforlife 20.02.2019 18:44

Вы не можете комбинировать, если ID1 и ID2 не совпадают. Если они одинаковы, вы должны проверить, существует ли уже ключ, потому что вы не можете иметь одинаковые ключи в словаре.

jdweng 20.02.2019 18:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
113
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

// lets group all of our id's and I'm not going to use groupby because I'm not a fan.
var itemsById = new Dictionary<string, List<MyDto>>();
foreach(var item in q)
{
   if (itemsById.ContainsKey(item.SomeId))
   {
       itemsById[item.SomeId].Add(item);
   }
   else 
   {
      itemsById.Add(item.SomeId, new List<MyDto>());
      itemsById[item.SomeId].Add(item);
   } 
}

so now we have dictionary of all of items by their ID.

var finalizedDtos = new List<MyDto>();
foreach(var entry in items)
{
   var finalizedDto = new MyDto{ someId = entry.Key };
   foreach(var innerDictionary in entry.value.JsonDictionary)
   {
                    var finalizedDto = new MyDto {SomeId = entry.Key};
                    var allKeyValuePairs = entry.Value.SelectMany(c => c.JsonDictionary);
                    finalizedDto.JsonDictionary = allKeyValuePairs.ToDictionary(key => key.Key, value => value.Value);
                    finalizedDtos.Add(finalizedDto);
   }
}

Не так много linq, но на самом деле для вложенной структуры я не мог придумать лучшего плана.

Спасибо, Jlalonde, я столкнулся с некоторыми конфликтами с этим кодом... но в любом случае, спасибо!!

user3814711 20.02.2019 22:09
Ответ принят как подходящий

Это работает, если вы хотите сделать это таким образом... Однако вы не указали, как вы хотите обрабатывать конфликты с JsonDictionaries с тем же ключом, но с другим значением. В этом сценарии я просто переопределяю ранее объявленные значения. Вам придется изменить это, если вы хотите другое поведение.

IEnumerable<MyDto> list = new List<MyDto>(); // This is the stuff you parsed
var results = new Dictionary<Tuple<Guid, Guid>, MyDto>();

foreach (var item in list) {
    var key = new Tuple<Guid, Guid>(item.SomeId1, item.SomeId2);
    if (results.ContainsKey(key))
        foreach (var entry in item.JsonDictionary)
            results[key].JsonDictionary[entry.Key] = entry.Value;
    else results[key] = item;
}

list = results.Values;

ОБНОВИТЬ:

Я написал это в Linq, если вы действительно этого хотите. Это довольно неэффективно, но я не мог придумать много других способов сделать это легко. Если вам нужна эффективность, вы должны использовать приведенный выше пример.

var results = list
    .GroupBy(
        x => new Tuple<Guid, Guid>(x.SomeId1, x.SomeId2), 
        (x, y) => new MyDto {
                SomeId1 = x.Item1,
                SomeId2 = x.Item2,
                JsonDictionary = y
                    .SelectMany(z => z.JsonDictionary)
                    .ToLookup(z => z.Key, z => z.Value)
                    .ToDictionary(z => z.Key, z => z.First())
        });

Отлично @Aotn! Спасибо!!

user3814711 20.02.2019 21:59

Другие вопросы по теме