Peladao
Peladao

Reputation: 4090

How to select multiple values from a Dictionary using Linq as simple as possible

I need to select a number of values (into a List) from a Dictionary based on a subset of keys.

I'm trying to do this in a single line of code using Linq but what I have found so far seems quite long and clumsy. What would be the shortest (cleanest) way to do this?

This is what I have now (the keys are Strings and keysToSelect is a List of keys to select):

List<ValueType> selectedValues = dictionary1.Where(x => keysToSelect.Contains(x.Key))
                                            .ToDictionary<String, valueType>(x => x.Key,
                                                                             x => x.Value)
                                            .Values.ToList;

Thank you.

Upvotes: 48

Views: 62977

Answers (6)

Good Night Nerd Pride
Good Night Nerd Pride

Reputation: 8500

Another option that doesn't do work twice:

var dict = new Dictionary<int, string> {
    [1] = "one",
    [2] = "two",
    [3] = "three",
    [4] = "four"
};
var keys = new[] { 2, 4, 1 };

var result = dict
    .Join(keys, x => x.Key, k => k, (x, _) => x.Value)
    .ToArray();

Upvotes: 0

Alex from Jitbit
Alex from Jitbit

Reputation: 60902

The accepted answer is not very efficient when keys are not guaranteed to exist b/c it performs two lookups.

Based on the accepted answer I came up with this extension method:

public static IEnumerable<TValue> GetMultiple<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, IEnumerable<TKey> keysToSelect)
{
    foreach (var key in keysToSelect)
        if (dictionary.TryGetValue(key, out TValue value))
            yield return value;
}

Not exactly a "one liner" but I find it more readable than chaining four Linq methods.

Usage:

var results = dictionary.GetMultiple(keysToSelect).ToList()

Upvotes: 5

Yinzara
Yinzara

Reputation: 842

The accepted solution is still not the most efficient option from the point of lookups as you still have to check if the key is in the dictionary twice: once to filter the keys, once to lookup the object.

This solution does not have that issue:

var selectedValues = keysToSelect
  .Select(_ => {
     var found = dict.TryGetValue(_, out TValue? result);
     return (found, result);
  })
  .Where(_ => _.found)
  .Select(_ => _.result!)
  .ToList();

Upvotes: 1

verdesmarald
verdesmarald

Reputation: 11866

Well you could start from the list instead of the dictionary:

var selectedValues = keysToSelect.Where(dictionary1.ContainsKey)
                     .Select(x => dictionary1[x])
                     .ToList();

If all the keys are guaranteed to be in the dictionary you can leave out the first Where:

var selectedValues = keysToSelect.Select(x => dictionary1[x]).ToList();

Note this solution is faster than iterating the dictionary, especially if the list of keys to select is small compared to the size of the dictionary, because Dictionary.ContainsKey is much faster than List.Contains.

Upvotes: 77

Guffa
Guffa

Reputation: 700830

If you know that all the value that you want to select are in the dictionary, you can loop through the keys instead of looping through the dictionary:

List<ValueType> selectedValues = keysToSelect.Select(k => dictionary1[k]).ToList();

Upvotes: 3

jeroenh
jeroenh

Reputation: 26792

A Dictionary<TKey,TValue> is IEnumerable<KeyValuePair<TKey,TValue>>, so you can simply Select the Value property:

 List<ValueType> selectedValues = dictionary1
           .Where(x => keysToSelect.Contains(x.Key))
           .Select(x => x.Value)
           .ToList();

or

 var selectValues = (from keyValuePair in dictionary1
                     where keysToSelect.Contains(keyValuePair.Key)
                     select keyValuePair.Value).ToList()

Upvotes: 9

Related Questions