LINQ: получение ключей для заданного списка значений из словаря и наоборот - PullRequest
16 голосов
/ 27 июня 2011

В моем коде есть следующая структура Dictionary<TKeys, TValues> data;.Я запускаю несколько запросов LINQ для обоих типов данных, и мне часто приходится переключаться между Keys и Values.Каков наилучший способ получить список ключей для заданных значений и наоборот?Пожалуйста, обратите внимание, что у меня обычно есть «IEnumerable» и «IEnumerable» в результате моих предыдущих запросов LINQ и я хотел бы иметь что-то вроде IEnumerable<TKeys> Dictionary.GetAllKeys(IEnumerable<IValues> vals) и IEnumerable<TValues> Dictionary.GetAllValues(IEnumerable<IKeys> keys).

Может быть, мне нужен другой контейнер данныхза эту задачу?

С уважением, Александр.

Ответы [ 3 ]

31 голосов
/ 27 июня 2011
 var values = dictionary.Where(x => someKeys.Contains(x.Key)).Select(x => x.Value);
 var keys = dictionary.Where(x => someValues.Contains(x.Value)).Select(x => x.Key);
11 голосов
/ 27 июня 2011

A Dictionary<,> действительно не подходит для поиска ключей по значению. Вы можете написать двунаправленный словарь, как Я сделал в этом ответе , но он не будет обязательно лучшим подходом.

Конечно, вы можете использовать словарь как последовательность пар ключ / значение, чтобы вы могли иметь:

var keysForValues = dictionary.Where(pair => values.Contains(pair.Value))
                              .Select(pair => pair.Key);

Просто знайте, что это будет операция O (n), даже если ваши "значения" - это HashSet или что-то подобное (с эффективной проверкой содержимого).

РЕДАКТИРОВАТЬ: Если вам действительно не нужно отношение ключ / значение - если это больше похоже на пары - тогда использование List<Tuple<Foo, Bar>> будет иметь определенный смысл. Запрос в конечном итоге остается тем же:

public IEnumerable<T1> GetAllFirst<T1, T2>(IEnumerable<Tuple<T1, T2>> source,
                                           IEnumerable<T2> seconds)
{
    HashSet<T2> secondsSet = new HashSet<T2>(seconds);
    return source.Where(pair => secondsSet.Contains(pair.Item2));
}

public IEnumerable<T2> GetAllSecond<T1, T2>(IEnumerable<Tuple<T1, T2>> source,
                                            IEnumerable<T1> firsts)
{
    HashSet<T1> firstsSet = new HashSet<T1>(firsts);
    return source.Where(pair => firstsSet.Contains(pair.Item1));
}
1 голос
/ 27 июня 2011

Лучший подход - выполнить запрос linq для набора пар ключ-значение, а затем использовать проекцию Выбрать, чтобы выбрать ключи или значения в конце запроса.Таким образом, нет необходимости выполнять поиск в конце вашего запроса.

Например:

  Dictionary<string, string> data = new Dictionary<string, string>();
  // select all values for keys that contain the letter 'A'
  var values = data.Where(pair => pair.Key.Contains("A"))
                   .Select(pair => pair.Value);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...