Ivan
Ivan

Reputation: 64207

How to write a LINQ query resulting in a Dictionary?


public class Person
{
    public string NickName{ get; set; }
    public string Name{ get; set; }
}

var pl = new List<Person>;

var q = from p in pl
        where p.Name.First() == 'A'
        orderby p.NickName
        select new KeyValuePair<String, String>(p.NickName, p.Name);

var d1 = q.ToList(); // Gives List<KeyValuePair<string, string>>
var d2 = q.ToDictionary(); // Does not compile

How to get Dictionary<string, string>?

Upvotes: 42

Views: 3624

Answers (6)

Jodrell
Jodrell

Reputation: 35696

EDIT

If you really feel you need to get from IEnumerable<KeyValuePair<TKey, TValue>> to a Dictionary implicitly you could add this extension.

public static IDictionary<TKey, ToValue> ToDictionary<TKey, TValue>(
    this IEnumerable<KeyValuePair<TKey, TValue>> source)
{
    return source.ToDictionary(p => p.Key, p => p.Value);
}

Then you could call ToDictionary() on any IEnumerable<KeyValuePair<TKey, TValue>>.

EDIT 2

If you are anticipating duplicates then you could create a ToLookup() extension too.

public static ILookup<TKey, TValue> ToLookup<TKey, TValue>(
    this IEnumerable<KeyValuePair<TKey, TValue>> source)
{
    return source.ToLookup(p => p.Key, p => p.Value);
}

Alternatively, if you really want to discard results, you could add an overload for ToDictionary.

public static IDictionary<TKey, ToValue> ToDictionary<TKey, TValue>(
    this IEnumerable<KeyValuePair<TKey, TValue>> source,
    Func<<IEnumerable<TValue>, TValue> selector)
{
    return source
        .Lookup(p => p.Key, p => p.Value);
        .ToDictionary(l => l.Key, l => selector(l));
}

If you arbitrarily discard all but the "first" (what does that mean without an OrderBy) item, you could use this extension like this,

pairs.ToDictionary(v => v.First()); 

Overall, you can remove most of your code and do,

var q = from p in pl
        where p.Name.First() == 'A'
        select p;
var d = q.ToDictionary(p => p.NickName, p => p.Name);

If there could be duplicates, do

var d = q.ToLookup(p => p.NickName, p => p.Name);

but note, this returns an ILookup<TKey, TElement>, the Item indexer of which, returns an IEnumerable<TElement> so you don't discard data.

Upvotes: 7

AmazedMouse
AmazedMouse

Reputation: 1

You can get Dictionary from LINQ query also by casting it :

var d2 = (Dictionary<string, string>)q;

This worked on Visual Studio 2013.

Upvotes: -1

bhamby
bhamby

Reputation: 15440

I realize that this was tagged with , but I was literally just trying to figure out how to do this in yesterday, so I thought I would share how you'd do this in VB as well:

Public Class Person
    Property NickName As String
    Property Name As String
End Class

Sub Main()
    Dim p1 As New List(Of Person)

    '*** Fill the list here ***

    Dim q = (From p In p1
             Where p.Name.First = "A"
             Select p.NickName, p.Name).ToDictionary(
                                           Function(k) k.NickName, 
                                           Function(v) v.Name)
End Sub

Upvotes: 0

Neil Knight
Neil Knight

Reputation: 48537

You need to specify the values for the Dictionary

var d2 = q.ToDictionary(p => p.NickName, p => p.Name);

Upvotes: 43

Tim Schmelter
Tim Schmelter

Reputation: 460028

A dictionary cannot contain multiple equal keys, so you should ensure (or know) that this is not the case. You could use GroupBy to ensure it:

Dictionary<string, string> dict = pl
        .Where(p => p.Name.First() == 'A')
        .GroupBy(p => p.NickName)
        .ToDictionary(g => g.Key, g => g.First().Name); 

Upvotes: 11

Tilak
Tilak

Reputation: 30688

Try following for NickName as Key, and Name as Value

var d2 = q.ToDictionary (p => p.NickName, p=>p.Name);

But note that dictionary does not allow duplicate, so above will throw error for duplicate records with same nickname. Perhaps you would like to use Lookup that is similar to Dictionary, but allows duplicates

var d2 = q.ToLookup (p => p.NickName, p=>p.Name);

Upvotes: 5

Related Questions