2015-10-18 2 views
2

У меня есть два List<Dictionary<string, string>>Группа словарей с Linq

List<Dictionary<string, string>> ListdicA = new List<Dictionary<string, string>>(); 
Dictionary<string, string> dic1 = new Dictionary<string, string>(); 
dic1.Add("Type1", "1"); 
dic1.Add("Type2", "A"); 
dic1.Add("Type3", "X"); 
Dictionary<string, string> dic2 = new Dictionary<string, string>(); 
dic2.Add("Type1", "2"); 
dic2.Add("Type2", "B"); 
dic2.Add("Type3", "Y"); 
ListdicA.Add(dic1); 
ListdicA.Add(dic2); 

List<Dictionary<string, string>> ListdicB = new List<Dictionary<string, string>>(); 
Dictionary<string, string> dic3 = new Dictionary<string, string>(); 
dic3.Add("Type1", "1"); 
dic3.Add("Type2", "C"); 
dic3.Add("Type3", "X"); 
Dictionary<string, string> dic4 = new Dictionary<string, string>(); 
dic4.Add("Type1", "2"); 
dic4.Add("Type2", "D"); 
dic4.Add("Type3", "Z"); 
ListdicB.Add(dic3); 
ListdicB.Add(dic4); 

Я хочу, чтобы объединить два списка и групповые значения их ключей. В результате получается List<Dictionary<string, List<string>>>. Во-первых, я хочу, чтобы объединить два списка:

Type1 1 
Type2 A 
Type3 X 

Type1 2 
Type2 B 
Type3 Y 

Type1 1 
Type2 C 
Type3 X 

Type1 2 
Type2 D 
Type3 Z 

И я хочу сгруппируйте его с помощью клавиш, результат выглядит следующим образом:

Type1 1 
Type2 A C 
Type3 X X 

Type1 2 
Type2 B D 
Type3 Y Z 
+0

Я не уверен, что понимаю логические условия группировки. Не могли бы вы изменить свой вопрос, чтобы включить подробную информацию о том, как следует выполнять различные группировки? –

+0

Я хочу объединить два списка и сгруппировать их по Type1 @Luc Morin –

+0

Вам нужно присоединиться к ключам двух словарей, используя внешнее соединение, так как вам нужно включить все ключи обоих словарей. См. Следующую веб-страницу: https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b – jdweng

ответ

1

основе Вопрос обновления:

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

1) Вам необходимо присоединиться к двум спискам. (ListdicA.Concat(ListdicB))

2) Группа всех словари величина Type1 ключа в каждых словарях. (GroupBy(x => x["Type1"]))

3) UnWrap всех товаров IGrouping<string,Dictionary<string,string>> к KeyValuePair<string,string> (SelectMany(y => y))

4) Снова Группа пары значения ключа Клав, так что вы присоединитесь значения одинаковых ключей вместе (GroupBy(y => y.Key))

5) UnWrap IGrouping<string,KeyValuePair<string,string>> в IEnumerable<KeyValuePair<string,List<string>>> (Select(y => new KeyValuePair<string, List<string>>(y.Key, y.Select(z => z.Value).ToList())))

6) Преобразование IEnumerable<IEnumerable<KeyValuePair<string,List<string>>>> в IEnumerable<Dictionary<string,List<string>>> (Select(x => x.ToDictionary(y => y.Key, y => y.Value)))

7) Наконец Преобразовать IEnumerable<Dictionary<string,List<string>>> в List<Dictionary<string, List<string>>> (ToList())

string groupby = "Type1"; 

List<Dictionary<string, List<string>>> result = 
    ListdicA.Concat(ListdicB).GroupBy(x => x[groupby]).Select(x => 
     x.SelectMany(y => y) // Put .Distinct() here to remove duplicates.(optional) 
      .GroupBy(y => y.Key).Select(y => new KeyValuePair<string, List<string>>(y.Key, y.Select(z => z.Value).ToList()))) 
       .Select(x => x.ToDictionary(y => y.Key, y => y.Value)).ToList(); 

foreach (var d in result) 
{ 
    foreach (var k in d) 
    { 
     Console.Write(k.Key + " : "); 
     foreach (var l in k.Value) 
     { 
      Console.Write(l + " "); 
     } 
     Console.WriteLine(); 
    } 
} 

Выходы

Type1 1 1 
Type2 A C 
Type3 X X 

Type1 2 2 
Type2 B D 
Type3 Y Z 

Как я отметил в комментарии (внутри кода), если вы удалите этот комментарий и поместите .Distinct() righ t там будет удалено дубликатов

List<Dictionary<string, List<string>>> result = 
    ListdicA.Concat(ListdicB).GroupBy(x => x[groupby]).Select(x => x.SelectMany(y => y) 
     .Distinct().GroupBy(y => y.Key) 
      .Select(y => new KeyValuePair<string, List<string>>(y.Key, y.Select(z => z.Value).ToList()))) 
       .Select(x => x.ToDictionary(y => y.Key, y => y.Value)).ToList(); 

будет выводиться.

Type1 1 
Type2 A C 
Type3 X 

Type1 2 
Type2 B D 
Type3 Y Z 

Если вы не хотите потерять X, то вам нужно пользовательские Distinct. Вам понадобится этот класс. (linq was taken and edited from here)

public static class SomeMoreLinq 
{ 
    public static IEnumerable<TSource> DistinctIf<TSource> 
     (this IEnumerable<TSource> source, Func<TSource, bool> keySelector) 
    { 
     HashSet<TSource> seenKeys = new HashSet<TSource>(); 
     foreach (TSource element in source) 
     { 
      if (seenKeys.Add(element) || !keySelector(element)) 
      { 
       yield return element; 
      } 
     } 
    } 
} 

И затем используйте его в своем запросе.

List<Dictionary<string, List<string>>> result = 
    ListdicA.Concat(ListdicB).GroupBy(x => x[groupby]).Select(x => x.SelectMany(y => y) 
     .DistinctIf(y => y.Key == groupby).GroupBy(y => y.Key) 
      .Select(y => new KeyValuePair<string, List<string>>(y.Key, y.Select(z => z.Value).ToList()))) 
       .Select(x => x.ToDictionary(y => y.Key, y => y.Value)).ToList(); 

будет выводиться.

Type1 1 
Type2 A C 
Type3 X X 

Type1 2 
Type2 B D 
Type3 Y Z 

Если у вас есть вопросы, задайте вопросы.

Хотя это полностью расплавило мой разум, но это была хорошая практика !.

+0

Спасибо вам большое, но я хочу, чтобы результат был List >>, не является словарем > –

+0

Вы можете объяснить больше о своей логике? ваш результат кажется совершенно неправильным. обновите свой вопрос и исправьте свой результат. @ VũBích –

+0

@ VũBích См. Обновление. Надеюсь, это поможет :) –

0

Если вы

ListdicA.Zip(ListdicB, (a,b) => a.Concat(b) 
.GroupBy(x => x.Key) 
.Select (g => new 
       { 
        g.Key, 
        Values = g.SelectMany(d => d.Value).Distinct() 
       })) 

вы получите этот результат:

Type 1 1 
Type 2 A 
     C 
Type 3 X 

Type 1 2 
Type 2 B 
     D 
Type 3 Y 
     Z 

я не уверен, является ли ваш X X результатом является преднамеренным или опечатка. Если это предназначено, я должен добавить еще немного логики.

Смежные вопросы