1

这可能是一个简单的问题,但答案却让我难以捉摸。

我有一组要转换为字典的字符串。

集合中的每个字符串都是我从正则表达式匹配中获得的以逗号分隔的值列表。我希望字典中每个条目的键是逗号分隔列表中的第四个元素,并且相应的值是逗号分隔列表中的第二个元素。

当我尝试直接调用 ToDictionary 时,我最终陷入了某种循环,似乎让我退出了我所在的 BackgroundWorker 线程:

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]);

当我手动创建字典时,一切正常:

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;
}

感谢您提供的任何帮助。

4

3 回答 3

3

问题很可能是密钥有重复。你有三个选择。

保留第一个条目 (这是您当前在foreach循环中所做的)

键只有一个条目,第一个出现 - 这意味着您可以拥有Dictionary

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

保留所有条目,分组

键将有多个条目(每个键返回一个Enumerable),并且您使用 aLookup而不是 a Dictionary

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

保留所有条目,展平

没有钥匙之类的东西,只是一个扁平的条目列表:

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

您也可以在此处使用元组 ( Tuple.Create(x[3], x[1]);) 代替。


注意:在这些情况下,您需要决定在哪里/是否希望键为大写或小写。我还没有做任何与此相关的事情。如果您想将密钥存储为上层,只需在上面的所有内容中更改x[3]x[3].ToUpper()

于 2012-05-17T01:40:32.387 回答
1

这将使Split每个字符串MoveFromItems','它们一起使第 4 项(第 3 索引)作为键和第 2 项(第 1 索引)作为值。

var dict = MoveFromItems.Select(x => x.Split(','))
                         .ToLookup(x => x[3], x => x[1]);
于 2012-05-17T01:27:08.433 回答
1

这将拆分每个项目并从第 4 个拆分值中选择键,并从第 2 个拆分值中选择值,全部放入字典中。

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

将字符串拆分两次是没有意义的,只是为了使用不同的索引。

这就像将拆分结果保存到一个局部变量中,然后使用它来访问索引 3 和 1。

但是,如果您确实不知道键是否会再次出现,那么毫无疑问,我会选择您实现的简单循环。

尽管您的循环中有一个小错误:

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;     
    }
}

ContainsKey(sKey.ToUpper())如果你真的想要所有大写的键,也应该在你的情况下这样做。

于 2012-05-17T01:27:12.047 回答