locked
Linq help with IEnumerable<KeyValuePair<string, string>> to a Dictionary<string, List<string>> RRS feed

  • Question

  • Seems to be a common issue, my use case is hampered by the fact I will enumerate multiple occurrences of the same key for which possibly non unique string values may be returned.

    Is there syntactically short linq that can produce this, I am accessing an api for which this pattern is rampant.

    public static class Extensions
    {
        public static Dictionary<string, List<string>> ToDictionary(this IEnumerable<KeyValuePair<string, string>> source)
        {
            Dictionary<string, List<string>> results = new Dictionary<string, List<string>>();
    
            foreach (KeyValuePair<string, string> kp in source)
            {
                if (results.ContainsKey(kp.Key))
                {
                    results[kp.Key].Add(kp.Value);
                }
                else
                {
                    results.Add(kp.Key, new List<string>() { kp.Value });
                }
            }
    
            return results;
        }
    }
    

    I know I can use extensions, but I am working towards some auto generated code and not relying hooks to insert boiler plate is a plus in this use case.

    Thanks!



    • Edited by Ritmo2k Tuesday, January 13, 2015 10:57 PM
    Tuesday, January 13, 2015 10:26 PM

Answers

  •  public static Dictionary<stringList<string>> ToDictionary(this IEnumerable<KeyValuePair<stringstring>> source)
            {
                return source
                    .GroupBy(
                        func => func.Key,
                        (key, list) => new { Key = key, Value = list.Select(f => f.Value).ToList() }
                        )
                    .ToDictionary(
                        func => func.Key,
                        func => func.Value
                        );
            }
    • Proposed as answer by Vineet Bharadwaj Wednesday, January 14, 2015 11:14 AM
    • Marked as answer by Ritmo2k Wednesday, January 14, 2015 11:16 PM
    Wednesday, January 14, 2015 11:14 AM

All replies

  • Hi Ritmo2k,

    Actually I think it's already a very simple code snippet, if you insist on using linq to do the samething, it may be like this:

    public static class Extensions
        {
            public static Dictionary<string, List<string>> ToDictionary(this IEnumerable<KeyValuePair<string, string>> source)
            {
                Dictionary<string, List<string>> results = new Dictionary<string, List<string>>();
    
                //use linq expression
                ((from kp in source
                  where results.ContainsKey(kp.Key)
                  select kp).ToList()).ForEach(kp => results[kp.Key].Add(kp.Value));
    
                ((from kp in source
                  where !results.ContainsKey(kp.Key)
                  select kp).ToList()).ForEach(kp => results.Add(kp.Key, new List<string>() { kp.Value }));
    
                //or use the extension methods
                //source.Where(kp => results.ContainsKey(kp.Key)).ToList().ForEach(kp => results[kp.Key].Add(kp.Value));
                //source.Where(kp => !results.ContainsKey(kp.Key)).ToList().ForEach(kp => results.Add(kp.Key, new List<string>() { kp.Value }));
    
                //foreach (KeyValuePair<string, string> kp in source)
                //{
    
                //    if (results.ContainsKey(kp.Key))
                //    {
                //        results[kp.Key].Add(kp.Value);
                //    }
                //    else
                //    {
                //        results.Add(kp.Key, new List<string>() { kp.Value });
                //    }
                //}
    
                return results;
            }
        }

    As you can see, using the extension method is the easist way to do what you want. So I recommend that you go in this way.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    • Edited by Caillen Wednesday, January 14, 2015 9:27 AM
    Wednesday, January 14, 2015 9:26 AM
  • Here is my preference

                List<List<object>> input = new List<List<object>>();
    
                Dictionary<object, List<List<object>>> dict = input.AsEnumerable()
                    .GroupBy(x => x[0], y => y)
                    .ToDictionary(x => x.Key, y => y.ToList());

    If you just have two column input then you can use this

                Dictionary<object, List<object>> dict = input.AsEnumerable()
                    .GroupBy(x => x[0], y => y[1])
                    .ToDictionary(x => x.Key, y => y.ToList());
    Note : the 2nd field of the dictionary is a list when you have a key with multiple values.  You don't need to list when you have a dictionary with a unique value for each key.


    Wednesday, January 14, 2015 10:52 AM
  •  public static Dictionary<stringList<string>> ToDictionary(this IEnumerable<KeyValuePair<stringstring>> source)
            {
                return source
                    .GroupBy(
                        func => func.Key,
                        (key, list) => new { Key = key, Value = list.Select(f => f.Value).ToList() }
                        )
                    .ToDictionary(
                        func => func.Key,
                        func => func.Value
                        );
            }
    • Proposed as answer by Vineet Bharadwaj Wednesday, January 14, 2015 11:14 AM
    • Marked as answer by Ritmo2k Wednesday, January 14, 2015 11:16 PM
    Wednesday, January 14, 2015 11:14 AM
  • Thanks everyone, this was all very informative as I have not used Linq extensively and seeing examples helped.
    Wednesday, January 14, 2015 11:18 PM