简体   繁体   中英

Converting Collection of Strings to Dictionary

This is probably a simple question, but the answer is eluding me.

I have a collection of strings that I'm trying to convert to a dictionary.

Each string in the collection is a comma-separated list of values that I obtained from a regex match. I would like the key for each entry in the dictionary to be the fourth element in the comma-separated list, and the corresponding value to be the second element in the comma-separated list.

When I attempt a direct call to ToDictionary, I end up in some kind of loop that appears to kick me of the BackgroundWorker thread I'm in:

var MoveFromItems = matches.Cast<Match>()
                           .SelectMany(m => m.Groups["args"].Captures
                           .Cast<Capture>().Select(c => c.Value));

var dictionary1 = MoveFromItems.ToDictionary(s => s.Split(',')[3], 
                                             s => s.Split(',')[1]);

When I create the dictionary manually, everything works fine:

var MoveFroms = new Dictionary<string, string>();

foreach(string sItem in MoveFromItems) 
{
    string sKey = sItem.Split(',')[3]; 
    string sVal = sItem.Split(',')[1];

    if(!MoveFroms.ContainsKey(sKey))
        MoveFroms[sKey.ToUpper()] = sVal;
}

I appreciate any help you might be able to provide.

The problem is most likely that the keys have duplicates. You have three options.

Keep First Entry (This is what you're currently doing in the foreach loop)

Keys only have one entry, the first one that shows up - meaning you can have a Dictionary :

var first = MoveFromItems.Select(x => x.Split(','))
                         .GroupBy(x => x[3])
                         .ToDictionary(x => x.Key, x => x.First()[1]);

Keep All Entries, Grouped

Keys will have more than one entry (each key returns an Enumerable ), and you use a Lookup instead of a Dictionary :

var lookup = MoveFromItems.Select(x => x.Split(','))
                          .ToLookup(x => x[3], x => x[1]);

Keep All Entries, Flattened

No such thing as a key, simply a flattened list of entries:

var flat = MoveFromItems.Select(x => x.Split(','))
                        .Select(x => new KeyValuePair<string,string>(x[3], x[1]));

You could also use a tuple here ( Tuple.Create(x[3], x[1]); ) instead.


Note: You will need to decide where/if you want the keys to be upper or lower case in these cases. I haven't done anything related to that yet. If you want to store the key as upper, just change x[3] to x[3].ToUpper() in everything above.

This will Split each string in MoveFromItems with ',' and from them make 4th item (3rd Index) as Key and 2nd item(1st Index) as Value.

var dict = MoveFromItems.Select(x => x.Split(','))
                         .ToLookup(x => x[3], x => x[1]);

This splits each item and selects key out of the 4th split-value, and value out of the 2nd split-value, all into a dictionary.

var dictionary = MoveFromItems.Select(s => s.Split(','))
                              .ToDictionary(split => split[3],
                                            split => split[1]);

There is no point in splitting the string twice, just to use different indices.

This would be just like saving the split results into a local variable, then using it to access index 3 and 1.

However, if indeed you don't know if keys might reoccur, I would go for the simple loop you've implemented, without a doubt.

Although you have a small bug in your loop:

MoveFroms = new Dictionary<string, string>();

foreach(string sItem in MoveFromItems) 
{
    string sKey = sItem.Split(',')[3]; 
    string sVal = sItem.Split(',')[1];

    // sKey might not exist as a key
    if (!MoveFroms.ContainsKey(sKey))
    //if (!MoveFroms.ContainsKey(sKey.ToUpper()))
    {
        // but sKey.ToUpper() might exist!
        MoveFroms[sKey.ToUpper()] = sVal;     
    }
}

Should do ContainsKey(sKey.ToUpper()) in your condition as well, if you really want the key all upper cases.

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