У меня есть словарь, ключ которого имеет строковый тип и значение списка целочисленного типа, например:
Dictionary<string, List<int>>
.
Допустим, я добавляю к нему элементы:
Dictionary<string, List<int>> check2 = new Dictionary<string, List<int>>();
check2.Add("LD010101", new List<int> { 1, 2, 3 });
check2.Add("LD010201", new List<int> { 1 });
check2.Add("LD030101", new List<int> { 2, 3, 4 });
check2.Add("LD030201", new List<int> { 1, 3, 4 });
check2.Add("LD040101", new List<int> { 5, 1, 4 });
check2.Add("LD050101", new List<int> { 1, 3, 4 });
Теперь я хочу применить группу на основе целочисленного значения и отфильтровать ее. Допустим, группировка по фильтру равна 2. Тогда на выходе должен быть такой словарь Dictionary<int, List<string>>
, поэтому при использовании фильтра 2 на выходе будет такой словарь, и для этого мне нужно использовать GroupBy
:
key:2, Value: {"LD010101","LD030101"}
Используйте комбинацию фильтрации (например, с помощью метода .Where()
LINQ) и List.Contains()
:
var filter = 2;
var value = check2
.Where(el => el.Value.Contains(filter))
.Select(el => el.Key)
.ToList();
var newDict = new Dictionary<int, List<string>> { { filter, value } };
можем ли мы сделать то же самое по группам? потому что я уже могу делать это.
Можно, но зачем вам это нужно? Ваша операция фильтра является двоичной (набор либо содержит, либо не содержит значение фильтра), поэтому группировка ничего не даст. Если вы хотите выполнить настоящую группировку, обновите вопрос, чтобы объяснить, что вы хотите сделать.
Этот метод является примером: он передает первые Dictionary<int, List<string>>
и filter
в качестве параметров и возвращает новый Dictionary<int, List<string>>
, который группирует первые ключи по фильтру.
public static Dictionary<int, List<string>> FilterDictionaryByGroup(Dictionary<string, List<int>> inputDict, int filter)
{
var grouped = inputDict
.Where(el => el.Value.Contains(filter))
.GroupBy(el => filter)
.ToDictionary(g => g.Key, g => g.Select(el => el.Key).ToList());
return grouped;
}
var result = FilterDictionary(check2, filter);
Имейте в виду, что этот подход обрабатывает только одно значение фильтра (например, в вашем случае 2
), но поскольку вы хотите, чтобы тип возвращаемого значения был Dictionary<int, List<string>>
, вы все равно можете придерживаться того же подхода, добавив List<int> filters
к аргументам метода вместо один int
и переберите их.
Предложение Where
говорит само за себя, оно перебирает каждый элемент и «фильтрует» его, возвращая только те элементы, значения которых List содержит фильтр (здесь, например, 2, поскольку это только то, что нам нужно).
g.Select(el => el.Key)
означает «для каждого элемента (el
) в группе (g
) выберите его ключ». При этом извлекаются ключи всех словарных статей в группе.
ToList()
преобразует выбранные ключи в список. Это необходимо, поскольку мы хотим, чтобы значение элемента словаря было List<string>
, а не общим IEnumerable<string>
, которое Select
возвращает.
отметив вас как ответ, но не могли бы вы немного объяснить, почему мы сначала применили предложение Where с filter=2 ? и что на самом деле делает "g => g.Select(el => el.Key).ToList()"?
Требование: учитывая целочисленное значение, дать мне все ключи Словаря, имеющие хотя бы одно значение, равное этому целочисленному значению, в списке, принадлежащем этому ключу.
Dictionary<TKey, TValue>
реализует ICollection<KeyValuePair<TKey,TValue>>
. Это означает, что вы можете перебирать элементы в словаре, как если бы они представляли собой комбинацию ключа и значения.
В вашем случае: строка и список.
Таким образом, из каждой пары <string, list> вы хотите сохранить только те, которые имеют хотя бы один раз заданное целочисленное значение в списке.
int searchValue = ...
Dictionary<string, List<int>> myDictionary = ...
IEnumerable<string> keysWithAtLeastOneSearchValueInTheList = myDictionary
.Where(keyValuePair => keyValuePair.Value.Contains(searchValue))
.Select(keyValuePair => kayValuePair.Key);
Другими словами: myDictionary также является перечислимой последовательностью KeyValuePairs, где Key — это строка, а значение — это список, принадлежащий этому ключу. Из этой перечислимой последовательности сохраняйте только те пары KeyValuePairs, значение свойства которых (= список целых чисел) содержит значение searchValue. Из оставшихся пар KeyValuePairs выберите Key (= string).
Самое простое решение, ИМХО, такое:
ILookup<int, string> lookup =
check2
.SelectMany(x => x.Value, (x, Value) => (x.Key, Value))
.ToLookup(x => x.Value, x => x.Key);
Затем вы можете получить желаемый результат следующим образом:
List<string> output = lookup[2].ToList();
Это дает:
LD010101
LD030101
Если вам нужно иметь это как Dictionary<int, List<string>>
, то это работает:
Dictionary<int, List<string>> lookup =
check2
.SelectMany(x => x.Value, (x, Value) => (x.Key, Value))
.ToLookup(x => x.Value, x => x.Key)
.ToDictionary(x => x.Key, x => x.ToList());
Чего не хватает (ИМО), так это того, что ожидается, когда фильтр «не найден». Один ответ (пока) «возвращает» фильтр и «пустой» список; какой самый полезный (ИМО); остальные просто возвращают «пустые» словари.