简体   繁体   中英

How can I transform a List <string> to a Dictionary<string, int>?

How can I transform a List <string> to a Dictionary<string, int> ?

This should be number from zero to n.

You can use ToDictionary() to create a Dictionary from any IEnumerable .

var list = new List<string>() { "Foo", "Bar", "Spam" };

// TKey is int, TValue is string
int i = 0;
Dictionary<int,string> dict1 = list.ToDictionary( _ => i++ );          

// TKey is string, TValue is int
i = 0;
Dictionary<string,int> dict2 = list.ToDictionary( x => x, _ => i++ );

The lambda passed to ToDictionary is the keySelector . Usually you use this to select a property from the items in the IEnumerable to be the key, but here, we use it to provide a count.

Edit: The second version uses two selectors. The first is the key. By providing a x => x lambda, we are just using the string that came from the list. The second selector is the value. Here, we are providing the counter, i .


Performance

I decided to test out the performance of my method versus pst's method.

Test Code:

static void Main(string[] args) {
    const int N = 1000000;
    const int M = 10;
    Stopwatch s;

    // Generate test list of strings.
    var list = Enumerable.Range(0, N).Select(n => n.ToString());

    // Just so it's enumerated once before.
    var ar = list.ToArray(); 

    // Try Jonathon's method M times.
    s = Stopwatch.StartNew();
    for (int x = 0; x < M; x++) {
        int i = 0;
        //var dict1 = list.ToDictionary(_ => i++);    // Before question edit
        var dict1 = list.ToDictionary(x => x, _ => i++);
    }
    s.Stop();
    Console.WriteLine("Jonathon's i++ method took {0} ms", s.ElapsedMilliseconds);

    // Try pst's method M times.
    s = Stopwatch.StartNew();
    for (int x = 0; x < M; x++) {
        var dict2 = list.Select((v, j) => new {v, j}).ToDictionary(p => p.v, p => p.j);
    }
    s.Stop();
    Console.WriteLine("psts' Select() method took {0} ms", s.ElapsedMilliseconds);

    Console.ReadLine();
}

Output:

Jonathon's i++ method took 3005 ms
pst's Select() method took 5019 ms

Output (After question edit):

Jonathon's i++ method took 3521 ms
pst's Select() method took 5103 ms

In conclusion, it appears that there is a roughly 40% improvement by using a counter instead of creating the intermediate, anonymous-typed objects.

Assuming that each item maps to the key and and n represents the index in the source, then:

var dict = list
    .Select((v, i) => new {v, i})
    .ToDictionary(p => p.v, p => p.i);

I like this approach because, while the temporary anonymous type is a little wonky, it's a self-contained side-effect free expression.

(This will throw an exception if there are any duplicate items in the source list.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM