gartenriese
gartenriese

Reputation: 4356

Select Value from Dictionary if Key exists using LINQ

I have a dictionary where I have a List as value. I want to select specific elements from the list that belongs to a specific key. I tried this so far:

Dictionary<int, List<bool>> dic = new Dictionary<int, List<bool>>();
dic.Add(1, new List<bool> { true, true, false });
var works = dic.Where(x => x.Key == 1).SingleOrDefault().Value.Where(x => x == true).ToList();
var doesNotWork = dic.Where(x => x.Key == 2).SingleOrDefault().Value.Where(x => x == true).ToList();

The first LINQ works because there is a key equal to 1. Thus I get a List<bool> with two elements. The second LINQ does not work because Value is null. How can I rewrite that LINQ such that if there is no suitable key in the dictionary I get an empty List<bool>?

I thought my approach would work because I thought the default element had an empty list instead of null as Value.

Upvotes: 2

Views: 19528

Answers (7)

Gordon Allocman
Gordon Allocman

Reputation: 778

Disclaimer: This only works on C# 6.0 and later (VS 2015+)

If you really want to do it in a single line using linq you can use the ?. operator (null-conditional operator) and get a line like this:

var shouldWork = dic.Where(x => x.Key == 2)?.SingleOrDefault().Value.Where(x => x == true).ToList() ?? new List<bool>();

This will set shouldWork to either the result of the linq query or an empty list. You can replace new List<bool>() with anything you want

See MSDN post here and Github post here for information on the new features in C# 6.0 specifically this example from the github site:

int length = customers?.Length ?? 0; // 0 if customers is null

and description of how it works

The null-conditional operator exhibits short-circuiting behavior, where an immediately following chain of member accesses, element accesses and invocations will only be executed if the original receiver was not null

Edit: Since ?. checks for null, you could simplify the above linq query to this:

var shouldWork = dic[key]?.Where(x => x == true).ToList() ?? new List<bool>();

where key is some variable holding your key

Upvotes: 5

Ivan Stoev
Ivan Stoev

Reputation: 205569

You shouldn't be using LINQ to find a key in a Dictionary - the Dictionary has more efficient methods for doing that - ContainsKey/ indexer pair or more optimal TryGetValue.

For instance:

int key = 2;

(A)

var result = dic.ContainsKey(key) ? dic[key].Where(x => x == true).ToList() : new List<bool>();

(B)

List<bool> values;
var result = dic.TryGetValue(key, out values) ? values.Where(x => x == true).ToList() : new List<bool>();

Upvotes: 5

Andres GR
Andres GR

Reputation: 47

We don't know why it need to be LINQ, but this could be a option:

var nowItWork = dic.Where(x => x.Key == 2).SelectMany(x => x.Value).Where(x => x).ToList();

Upvotes: 0

konzuk
konzuk

Reputation: 31

Try this

Dictionary<int, List<bool>> dic = new Dictionary<int, List<bool>>();
dic.Add(1, new List<bool> { true, true, false });
var works = !dic.ContainsKey(1)? new List<bool>(): dic[1].Where(x => x == true).ToList();
var doesNotWork = !dic.ContainsKey(2) ? new List<bool>(): dic[2].Where(x => x == true).ToList();

Upvotes: 0

Nikolay Fedorov
Nikolay Fedorov

Reputation: 387

You want to get a strange result, but anyway this code help you:

 var reslt = (dic.FirstOrDefault(x => x.Key == 2).Value ?? new List<bool>(0))
.Where(x => x)
.ToList();

Using method SingleOrDefault() isn't correct, because key in Dictionary is unique.

And x=>x==true is strange too.

Upvotes: 0

paparazzo
paparazzo

Reputation: 45096

Why does it need to be LINQ?

List<bool> works1 = dic.ContainsKey(1) ? dic[1] : new List<bool>();

Upvotes: 1

mwilczynski
mwilczynski

Reputation: 3082

Simplest solution would be to use Dictionary<T>.TryGetValue so that you don't check twice for a value, ie:

        Dictionary<int, List<bool>> dic = new Dictionary<int, List<bool>>();
        dic.Add(1, new List<bool> { true, true, false });

        List<bool> match = null;
        var found = dic.TryGetValue(2, out match);
        if (!found) match = new List<bool>();

Upvotes: 0

Related Questions