Rich
Rich

Reputation: 36816

Select a Dictionary<T1, T2> with LINQ

I have used the "select" keyword and extension method to return an IEnumerable<T> with LINQ, but I have a need to return a generic Dictionary<T1, T2> and can't figure it out. The example I learned this from used something in a form similar to the following:

IEnumerable<T> coll = from x in y 
    select new SomeClass{ prop1 = value1, prop2 = value2 };

I've also done the same thing with extension methods. I assumed that since the items in a Dictionary<T1, T2> can be iterated as KeyValuePair<T1, T2> that I could just replace "SomeClass" in the above example with "new KeyValuePair<T1, T2> { ...", but that didn't work (Key and Value were marked as readonly, so I could not compile this code).

Is this possible, or do I need to do this in multiple steps?

Thanks.

Upvotes: 208

Views: 200093

Answers (4)

Quintin Robinson
Quintin Robinson

Reputation: 82345

The extensions methods also provide a ToDictionary extension. It is fairly simple to use, the general usage is passing a lambda selector for the key and getting the object as the value, but you can pass a lambda selector for both key and value.

class SomeObject
{
    public int ID { get; set; }
    public string Name { get; set; }
}

SomeObject[] objects = new SomeObject[]
{
    new SomeObject { ID = 1, Name = "Hello" },
    new SomeObject { ID = 2, Name = "World" }
};

Dictionary<int, string> objectDictionary = 
    objects.ToDictionary(
        o => o.ID, 
        o => o.Name);

Then objectDictionary[1] Would contain the value "Hello"

Upvotes: 363

M.Wolff
M.Wolff

Reputation: 131

I modified the solution of hross because his version puts alle items of an array into one dictionary element.

I wanted to have each array item in its own dictionary item. This has two advantages:

  • It is easier to work with if you have arrays which contain objects or other array instead of values.
  • The dictionary key is compatible with the JSON path of Json.Net.

The key to this solution is the fact that JToken knows its path (JToken.Path) so it is not necessary to assemble it for yourself. This makes the new solution surprisingly simple.

public static Dictionary<string, string?>? GetJsonDictionary(JToken? token)
{
    if (token == null)
    {
        return null;
    }
    var dict = new Dictionary<string, string?>();
    ParseJToken(token, dict);
    return dict;
}

private static void ParseJToken(JToken token, Dictionary<string, string?> nodes)
{
    if (token.HasValues)
    {
        // The node has children.
        foreach (JToken child in token.Children())
        {
            ParseJToken(child, nodes);
        }
    }
    else
    {
        // The node is a leaf.
        nodes.Add(token.Path, token.ToString());
    }
}

Upvotes: 0

Antoine Meltzheim
Antoine Meltzheim

Reputation: 9924

A more explicit option is to project collection to an IEnumerable of KeyValuePair and then convert it to a Dictionary.

Dictionary<int, string> dictionary = objects
    .Select(x=> new KeyValuePair<int, string>(x.Id, x.Name))
    .ToDictionary(x=>x.Key, x=>x.Value);

Upvotes: 75

albertein
albertein

Reputation: 27118

var dictionary = (from x in y 
                  select new SomeClass
                  {
                      prop1 = value1,
                      prop2 = value2
                  }
                  ).ToDictionary(item => item.prop1);

That's assuming that SomeClass.prop1 is the desired Key for the dictionary.

Upvotes: 46

Related Questions