#c# #dictionary
#c# #словарь
Вопрос:
У меня есть словарь, который выглядит следующим образом:
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>()
{
{"a" , new List<string> { "Red","Yellow"} },
{"b" , new List<string> { "Blue","Red"} },
{"c" , new List<string> { "Green","Orange"} },
{"d" , new List<string> { "Black","Green"} },
};
Мне нужен вывод в виде словаря из dict
, где общим значением в List<string>
должен быть ключ, а значением должен быть список ключей.
Например.:
Red: [a,b]
Green: [c,d]
Я не знаю, как решить эту проблему с помощью list
in dictionary
as TValue
.
Пожалуйста, объясните мне, как обрабатывать списки с помощью in dictionary.
Ответ №1:
Вы можете дополнить свой словарь с помощью SelectMany
и получить простой список, который выглядит как
"a" - "Red"
"a" - "Yellow"
"b" - "Blue"
"b" = "Red"
// and so on
затем сгруппируйте по значению и создайте новый словарь из этих групп. Попробуйте этот код:
var commonValues = dict.SelectMany(kv => kv.Value.Select(v => new {key = kv.Key, value = v}))
.GroupBy(x => x.value)
.Where(g => g.Count() > 1)
.ToDictionary(g => g.Key, g => g.Select(x => x.key).ToList());
Ответ №2:
Много зацикливаний… Выполните цикл по словарю, затем выполните цикл по каждому значению в списке.
var result = new Dictionary<string, List<string>>();
// Loop through each key/value pair in the dictionary
foreach (var kvp in dict)
{
// kvp.Key is the key ("a", "b", etc)
// kvp.Value is the list of values ("Red", "Yellow", etc)
// Loop through each of the values
foreach (var value in kvp.Value)
{
// See if our results dictionary already has an entry for this
// value. If so, grab the corresponding list of keys. If not,
// create a new list of keys and insert it.
if (!result.TryGetValue(value, out var list))
{
list = new List<string>();
result.Add(value, list);
}
// Add our key to this list of keys
list.Add(kvp.Key);
}
}
Если вы хотите отфильтровать это по записям, содержащим более одного элемента, то вы можете сделать:
result = result.Where(x => x.Value.Count > 1).ToDictionary(x => x.Key, x => x.Value);
В качестве альтернативы вы можете избежать циклов и вместо этого использовать Linq:
// Flatten the dictionary into a set of tuples
// e.g. (a, Red), (a, Yellow), (b, Blue), (b, Red), etc
var result = dict.SelectMany(kvp => kvp.Value.Select(color => (key: kvp.Key, color)))
// Group by the value, taking the color as the elements of the group
// e.g. (Red, (a, b)), (Yellow, (a)), etc
.GroupBy(item => item.color, item => item.key)
// Filter to the ones with more than one item
.Where(group => group.Count() > 1)
// Turn it into a dictionary, taking the key of the grouping
// (Red, Green, etc), as the dictionary key
.ToDictionary(group => group.Key, group => group.ToList());
Вы также можете использовать синтаксис запроса linq, который немного длиннее, но позволяет избежать путаницы вокруг SelectMany
:
var result =
(
from kvp in dict
from color in kvp.Value
group kvp.Key by color into grp
where grp.Count() > 1
select grp
).ToDictionary(grp => grp.Key, grp => grp.ToList());
Комментарии:
1. В
foreach
цикле это не позволяет мне инициализироватьlist
вTryGetValue()
методе. Итак, я делал это раньше, почему это так?2. @Watarap вы используете более старую версию C #. «Переменные Out» были введены в C # 7.0.
3. Я использую @canton7 . NET framework 4.7.2, поэтому я думаю, что c # версии 7.0 plus. У меня это работает, это не позволяет мне объявлять подобным образом
if (!result.TryGetValue(value, out var list))
. Я должен объявить переменную listList<string> list; if (!result.TryGetValue(value, out list))
, чтобы она скомпилировалась.4. @Watarap Для C # 7.0 вам понадобится Visual Studio 2017. Убедитесь, что он выбран в Project -> Properties -> Build -> Advanced -> Language version. Впрочем, это не имеет значения — можно сделать то, что вы сделали, и результат будет тот же.
5. @canton7 вы правы, я действительно использую c # 6.0 в Visual Studio 2015, только что проверил это. И последний вопрос, почему при его использовании объект должен реализовывать IConvertible . Этот проект не основан на консольном приложении, и я не смог выяснить, что вызывает эту ошибку.