Применить группировку к значению словаря

У меня есть словарь, ключ которого имеет строковый тип и значение списка целочисленного типа, например: 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"}

Чего не хватает (ИМО), так это того, что ожидается, когда фильтр «не найден». Один ответ (пока) «возвращает» фильтр и «пустой» список; какой самый полезный (ИМО); остальные просто возвращают «пустые» словари.

Gerry Schmitz 16.07.2024 19:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
54
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Используйте комбинацию фильтрации (например, с помощью метода .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 } };

можем ли мы сделать то же самое по группам? потому что я уже могу делать это.

sst 16.07.2024 12:19

Можно, но зачем вам это нужно? Ваша операция фильтра является двоичной (набор либо содержит, либо не содержит значение фильтра), поэтому группировка ничего не даст. Если вы хотите выполнить настоящую группировку, обновите вопрос, чтобы объяснить, что вы хотите сделать.

Neil T 16.07.2024 12:31
Ответ принят как подходящий

Этот метод является примером: он передает первые 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()"?

sst 16.07.2024 13:06

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

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

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