27

I have a string like string strn = "abcdefghjiklmnopqrstuvwxyz" and want a dictionary like:

Dictionary<char,int>(){
    {'a',0},
    {'b',1},
    {'c',2},
    ...
}

I've been trying things like

strn.ToDictionary((x,i) => x,(x,i)=>i);

...but I've been getting all sorts of errors about the delegate not taking two arguments, and unspecified arguments, and the like.

What am I doing wrong?

I would prefer hints over the answer so I have a mental trace of what I need to do for next time, but as per the nature of Stackoverflow, an answer is fine as well.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
mowwwalker
  • 16,634
  • 25
  • 104
  • 157
  • Why do you try it to do with linq? what is wrong with `var dict = new Dictionary(); foreach(char c in strn) dict.Add(c,c-'a');` – L.B Mar 23 '12 at 23:15
  • 2
    @L.B, Because I already know how to do that. I want to learn :D – mowwwalker Mar 23 '12 at 23:16
  • @L.B I borrowed the C# 4.0 in Depth from the library, and got about half way through it, but I wasn't committing much to memory without practicing, so I stopped reading. With this and the last question, I did look online before asking, and I did come to the same or similar conclusions that the answers offered, but, as a new programmer, I'm reluctant to trust what little experience I have and the few google results I saw against the combined wisdom of the stackoverflow community. – mowwwalker Mar 23 '12 at 23:23
  • @L.B, While you're here, can you answer the question I asked on Jon Skeet's answer? I legitimately don't know why the code he posted works the way it does. – mowwwalker Mar 23 '12 at 23:25
  • I don't know what you don't understand but maybe this rewrite may help `var dictionary = strn.Select((value, index) => new { v=value, i=index }).ToDictionary(pair => pair.v, pair => pair.i);` – L.B Mar 23 '12 at 23:30
  • @L.B, You were right, I looked it up in the MSDN docs and it was there. `If you do not specify member names in the anonymous type, the compiler gives the anonymous type members the same name as the property being used to initialize them`. Which, to me does seem like a very strange effect, as I've always disassociated variable names with the values they hold. – mowwwalker Mar 23 '12 at 23:34

3 Answers3

53

Use the .Select operator first:

strn
    .Select((x, i) => new { Item = x, Index = i })
    .ToDictionary(x => x.Item, x => x.Index);
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
9

What am I doing wrong?

You're assuming there is such an overload. Look at Enumerable.ToDictionary - there's no overload which provides the index. You can fake it though via a call to Select:

var dictionary = text.Select((value, index) => new { value, index })
                     .ToDictionary(pair => pair.value,
                                   pair => pair.index);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    @Walkerneo: Yes, that works. Why would it be `pair[0]`? `pair` is a reference to an instance of the anonymous inner type created in the `Select` call. – Jon Skeet Mar 23 '12 at 23:10
  • Alright, I tested it, and it worked, but I still can't say I understand why. I don't understand how the anonymous object has properties `value` and `index` which also have the values of those two variables. Is it shorthand for `new {value=value,index=index}`? – mowwwalker Mar 23 '12 at 23:13
  • @Walkerneo: Yes, that's exactly right. See the language spec's definitions of anonymous types for more information. – Jon Skeet Mar 24 '12 at 01:37
1

You could try something like this:

    string strn = "abcdefghjiklmnopqrstuvwxyz";

Dictionary<char,int> lookup = strn.ToCharArray()
    .Select( ( c, i ) => new KeyValuePair<char,int>( c, i ) )
        .ToDictionary( e => e.Key, e => e.Value );
Brandon Moretz
  • 7,512
  • 3
  • 33
  • 43