Manoj Nayak
Manoj Nayak

Reputation: 2509

Search For keys Matching values in a dictionary of list in C#

I have a dictionary of lists.

var dicAclWithCommonDsEffectivity = new Dictionary<string, List<int>>();
var list1 = new List<int>(){1,2,3};
var list2 = new List<int>(){2,4,6};
var list3 = new List<int>(){3,7,6};
var list4 = new List<int>(){8,7,6};

dicAclWithCommonDsEffectivity.Add("ab",list1);
dicAclWithCommonDsEffectivity.Add("bc",list2);
dicAclWithCommonDsEffectivity.Add("cd",list3);
dicAclWithCommonDsEffectivity.Add("de",list4);

I want to get the keys in dictionary for which atleast one matching value with the current key list. for key "ab"(first list). I should get: "ab","bc" and "cd".Since these lists contain one of the matching element in {1,2,3}

Is there a way without looping through each item in the list of dictionary value.

Upvotes: 1

Views: 12013

Answers (3)

Ian
Ian

Reputation: 30823

If what you mean is to visibly (not logically) remove the looping, you could use LINQ with proper Where filter to do that and Select the keys from the Dictionary which have any value element(s) intersect(s) with the selected List (List in the Dictionary with key == "ab") like this:

string key = "ab";
List<int> selectedList = dicAclWithCommonDsEffectivity[key];
var results = dicAclWithCommonDsEffectivity
    .Where(x => x.Value.Any(y => selectedList.Contains(y)))
    .Select(x => x.Key);

If you want to logically remove the looping too, please consider Mr. Skeet's answer.

Upvotes: 1

sujith karivelil
sujith karivelil

Reputation: 29036

It's always better to check for existence of the searchKey in the Dictionary before accessing them. Then you can get the associated list in the dictionary for that particular key.

You can also try like this:

string searchKey = "ab";
if (dicAclWithCommonDsEffectivity.ContainsKey(searchKey))
{
    var ListToSearch = dicAclWithCommonDsEffectivity[searchKey];
    var resultKeys = dicAclWithCommonDsEffectivity.Where(x => 
                                                 x.Value.Any(y => ListToSearch.Contains(y)))
                                                  .Select(x => x.Key)
                                                  .ToList();
}
else
{
    // Specified key was not found
}

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1503984

Is there a way without looping through each item in the list of dictionary value.

Something has to loop - dictionaries are only designed to look up by key, and you're not doing that other than for the first check.

You can do this fairly easily though:

private IEnumerable<string> GetMatchingKeys(
    Dictionary<string, List<int>> dictionary, string key)
{
    // TODO: Use TryGetValue if key might not be in dictionary
    HashSet<int> elements = new HashSet<int>(dictionary[key]);
    return dictionary.Where(pair => pair.Value.Any(x => elements.Contains(x)))
                     .Select(pair => pair.Key);
}

This uses the fact that Dictionary implements IEnumerable<KeyValuePair<TKey, TValue>> - so the Where clause checks a particular entry by spotting if any of the elements of its value matches any of the elements of the original value. The Select clause then projects the pair to just the key.

If you need to do this a lot and you're concerned about efficiency, another alternative would be to build a second dictionary from int to List<string> - basically a reverse mapping. You'd need to maintain that, but then you could easily fetch all the "original keys" mapping to each of the values corresponding to the given key, and just use Distinct to avoid duplicates.

Upvotes: 7

Related Questions