15

I have a dictionary:

Dictionary<String, List<Foo>> test = new Dictionary<String, List<Foo>>();

I then populate this dictionary hence why I need the list so I can call Add(). My problem is the function needs to return:

Dictionary<String, IEnumerable<Foo>>

Is there any easy way to do this without doing the obvious and looping through my original dictionary and doing it manually?

DasDave
  • 801
  • 1
  • 9
  • 28
  • 3
    Have you considered using a Lookup instead? That's typically a cleaner way of dealing with this type of thing. – Jon Skeet Feb 11 '15 at 10:23
  • 1
    Why don't you use a `Dictionary>` in the first place? How do you populate it? Maybe you can use `ToDictionary` similar as what Selman has used but in the first place when you populate it. – Tim Schmelter Feb 11 '15 at 10:24
  • It's a little difficult to explain without posting a lot of code. I have two different sources that I perform some calculations with and then create a new object, in this case Foo to store the results. – DasDave Feb 11 '15 at 10:26
  • 2
    @DasDave: You should really have a look at a [`Lookup`](https://msdn.microsoft.com/en-us/library/vstudio/bb460184%28v=vs.100%29.aspx) which you can get from `ToLookup` and which is a really nice class similar to a dictionary. But it's key doesn't need to be unique, nor does it need to exist and the value is an `IEnumerable` implicitely (empty if the key doesn't exist). – Tim Schmelter Feb 11 '15 at 10:30
  • @DasDave: also, you can always use a `List` if you want to use `Add` and finally add it to a `Dictionary>` via `dict.Add("foo", list)` since a `List` implements `IEnumerable`. – Tim Schmelter Feb 11 '15 at 10:49

3 Answers3

16
return dictionary.ToDictionary(x => x.Key,x => x.Value.AsEnumerable())
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • 1
    But it creates a new dictionary by looping the original dictionary which is what OP wants to avoid. – Tim Schmelter Feb 11 '15 at 10:23
  • 1
    it's also more efficient and easier to use the `List` to add things but add it to a `Dictionary>`. That's no problem since `List` implements `IEnumerable`, it's not even necessary to cast. – Tim Schmelter Feb 11 '15 at 10:53
  • @TimSchmelter this is the final result i went for. If you reformat into an answer i will mark as correct. Thank you. – DasDave Feb 11 '15 at 12:06
4

It's more efficient and easier to use the List<Foo> to add things but add it to a Dictionary<String, IEnumerable<Foo>>. That's no problem since List<Foo> implements IEnumerable<Foo>, it's not even necessary to cast.

So something like this(pseudo code):

var test = new Dictionary<String, IEnumerable<Foo>>();
foreach(var x in something)
{
    var list = new List<Foo>();
    foreach(var y in x.SomeCollection)
        list.Add(y.SomeProperty);
    test.Add(x.KeyProperty, list); // works since List<T> is also an IEnumerable<T>
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
0

I tried this route as well, converting Dictionary<string, List<Foo>> to a ReadOnlyDictionary<string, IEnumerable<Foo>>. While I was trying to convert to a read-only dictionary, the whole purpose of converting a List to IEnumerable is to make a read only collection. The problem with the OP's approach is:

Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();

errors["foo"] = new List<string>() { "You can't do this" };

Dictionary<string, IEnumerable<string>> readOnlyErrors = // convert errors...

readOnlyErrors["foo"] = new List<string>() { "I'm not actually read-only!" };

The appearance of IEnumerable<Foo> makes you think this is read only and safe, when in fact it is not. After reading the question LINQ Convert Dictionary to Lookup a Lookup object is more appropriate, because it allows you to:

  • Associate one key with multiple values

  • You cannot overwrite a key with a new value

    // This results in a compiler error
    lookUp["foo"] = new List<Foo>() { ... };
    
  • The "multiple values" are already defined as IEnumerable<T>

  • You can still use the same outer and inner loop algorithm to extract individual values:

    ILookup<string, string> lookup = // Convert to lookup
    
    foreach (IGrouping<string, string> grouping in lookup)
    {
        Console.WriteLine(grouping.Key + ":");
    
        foreach (string item in grouping)
        {
            Console.WriteLine("    item: " + item);
        }
    }
    

Convert Dictionary<string, List<Foo>> to ILookup<string, Foo>

It's a quick two-liner:

Dictionary<string, List<Foo>> foos = // Create and populate 'foos'

ILookup<string, Foo> lookup = foos.SelectMany(item => item.Value, Tuple.Create)
                                  .ToLookup(p => p.Item1.Key, p => p.Item2);

Now you can use the same two-step loop as you would have with a Dictionary<string, IEnumerable<Foo>>:

foreach (IGrouping<string, Foo> grouping in lookup)
{
    string key = grouping.Key;

    foreach (Foo foo in grouping)
    {
        // Do stuff with key and foo
    }
}

Source: LINQ Convert Dictionary to Lookup

Converting to another Dictionary with an IEnumerable value is like trying to stuff a square peg into a round hole. The more appropriate, and safe way (from an object-oriented standpoint) is to convert your read/write Dictionary to a Lookup. This gives you the true intended safety of an object that is read-only (except for the Foo items, which might not be immutable).

I would go so far as to say that most times when a ReadOnlyDictionary is used, you could use ILookup and get the same functionality.

Community
  • 1
  • 1
Greg Burghardt
  • 17,900
  • 9
  • 49
  • 92