Superbest
Superbest

Reputation: 26612

Generate a map of list element indices using Linq

I want to take a List, and generate a Dictionary which maps each element to its index in the List. I can do this like so, for a List<string>:

var myList = new List<string>{ /* populate list */ };
var orderMap = new Dictionary<string, int>();

foreach (var element in myList)
{
    orderMap[element] = myList.IndexOf(element);
}

Basically, I want to take a list like:

Apple
Banana
Orange

And return a map showing indices:

Apple -> 0
Banana -> 1
Orange -> 2

How can I do this with Linq? I think something like this should work:

orderMap = myList.Select( x => /* return a key value pair mapping x to myList.IndexOf(x) */ );

But I can't figure out the right syntax for it. Besides, can you refer to the list itself in the delegate used for Select?

Upvotes: 7

Views: 4611

Answers (3)

Botz3000
Botz3000

Reputation: 39630

You could try the ToDictionary extension method:

int index = 0; 
orderMap = myList.ToDictionary(x => x, x => index++);

Upvotes: 4

Greg B
Greg B

Reputation: 14898

Take a look at this overload of ToDictionary<TKey, TValue>(). It takes to functions to convert the input element into a Key and a Value.

e.g.

var myList = new List<string>{ /* populate list */ };
var orderMap = myList.ToDictionary(x => myList.IndexOf(x), x => x);

However, one problem with this is if the elements of myList aren't unique.

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1502556

While you can refer to the list within the delegate, it's not generally a good idea. You really want to use the overload of Select which provides the index as well as the value:

var dictionary = list.Select((value, index) => new { value, index })
                     .ToDictionary(p => p.value, p => p.index);

Note that this will throw an exception if you have any duplicate elements.

Upvotes: 15

Related Questions