Filtering a Dictionary by value with a List as the value

Filtering out entries in a dictionary is not too difficult when the key and value are simple.
For example if you had –

IDictionary oneToFourDictionary = new Dictionary {{ "one", 1 }, { "two", 2 }, { "three", 3 }, { "four", 4 } };

You could easily filter out all values greater than 2.

IDictionary onlyGreaterThanTwoDictionary = oneToFourDictionary.Where(pair => pair.Value > 2).ToDictionary(pair => pair.Key, pair => pair.Value);

But it gets a little more complex when you have a dictionary where the value is an IList any you want to filter out certain entries in the list. But fortunately this is not too difficult either when using the ConcurrentDictionary.

In the example below I am using a string as the key and list of ints as the value. Of course the same principle applies if your key and value are different.

I’m using a List as my filter, i.e. only numbers in this list are considered valid. Entries in the dictionary should be removed if the values are not in this list.

using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace ConcurrentDictionaryWithList
{
    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();

            IDictionary<string, IList<int>> unfilteredDictionary = p.PopulateUnfilteredDictionary();

            IList<int> filter = new List<int> {5, 1, 2};

            IDictionary<string, IList<int>> filteredDictionary =  p.Filter(filter, unfilteredDictionary);
        }

        private IDictionary<string, IList<int>> Filter(IList<int> filter, IDictionary<string, IList<int>> unfilteredDictionary )
        {
            ConcurrentDictionary<string, IList<int>> filteredResults = new ConcurrentDictionary<string, IList<int>>();

            foreach (KeyValuePair<string, IList<int>> unfilteredEntry in unfilteredDictionary)
            {
                foreach (int number in unfilteredEntry.Value)
                {
                    if (filter.Contains(number))
                    {
                        filteredResults.AddOrUpdate(unfilteredEntry.Key, new List<int> { number }, (key, value) => { value.Add(number);
                                                                                                                     return value;
                                                                                                                    });
                    }
                }
            }
            return filteredResults;
        }

        private IDictionary<string, IList<int>> PopulateUnfilteredDictionary()
        {
            IDictionary<string, IList<int>> unfilteredDictionary = new Dictionary<string, IList<int>>();
            unfilteredDictionary.Add("key1", new List<int> { 1, 2, 3, 4, 5 });
            unfilteredDictionary.Add("key2", new List<int> { 1, 7, 8, 9, 10 });
            unfilteredDictionary.Add("key3", new List<int> { 5, 10, 15 });
            unfilteredDictionary.Add("key4", new List<int> { 200, 300, 400 });

            return unfilteredDictionary;
        }


        // Showing the simple filter just for completeness. 
        private void SimpleDictionaryFilter()
        {
            IDictionary<string, int> oneToFourDictionary = new Dictionary<string, int> {{ "one", 1 }, { "two", 2 }, { "three", 3 }, { "four", 4 } };

            IDictionary<string, int> onlyGreaterThanTwoDictionary = oneToFourDictionary.Where(pair => pair.Value > 2)
                .ToDictionary(pair => pair.Key, pair => pair.Value);

        }
    }
}