简体   繁体   中英

How to merge n List<Dictionary<string, string>> into a Dictionary using Linq

I have tried to merge a list (dynamic) of dictionaries into one single list for a given object, using linq, I saw many questions similars to this one, however in their cases they always consider known number of dictionaries.

Well, this is my sctructure:

I have a query that returns a list objects like this:

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

using linq i am doing this:

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)
             });

At the end, I have a result like this;

{
  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.

As you can see, in the above snippet SomeId1 and SomeId2 of both objects are the same. So, in this case I would like to group these objects merging the JsonContent field into just one dictionary.

Also tried use .GroupBy but i have not been able to merge this jsonContent as an agregation.

Help!!! Please! =) Hugs

This works if you want to do it this way... However, you did not provide how you wanted to handle conflicts with JsonDictionaries with the same key but different value. In this scenario, I just overrode previously declared values. You'd have to change this if you wanted different behavior.

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;

UPDATE:

I wrote it in Linq if you really want it. It's pretty inefficient, but I couldn't think of many other ways to do this easily. If you want efficiency, you should use the above example.

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())
        });

So quick idea, not sure if this can be totally done in linq natively.

// 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);
   }
}

Not a whole lot of linq, but really for the nested structure I couldn't come up with a better plan

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM