【问题标题】:Splitting a string value inside list<>在 list<> 中拆分字符串值
【发布时间】:2013-02-14 12:42:02
【问题描述】:

我有一个包含在包含以下值的字典中的列表

value a
value b
value c
value 1, value 2, value3
value d

我想要的最终结果是

value a
value b
value c
value 1
value 2
value 3
value d

问题是遍历字典并尝试更改集合将不起作用,因为我试图在循环遍历它时对其进行修改

string[] ar;
        foreach (var kvp in dict)
        {
            if (kvp.Key == "STAR-016")
            {
                foreach (var v in kvp.Value)
                {
                    if (v.Contains(','))
                    {
                        ar = v.Split(',');
                        foreach (var a in ar)
                        {
                            kvp.Value.Add(a);
                        }
                    }
                }
            }
        }

我怎样才能得到想要的结果?

【问题讨论】:

  • 究竟想要达到什么目的?最终结果如何?
  • 您是否尝试过创建另一个列表并将每个结果都添加到该列表中?
  • 那么“value 1, value 2, value 3”是字符串文字吗?
  • 我认为这一切都在字典中的事实是过多的信息。这个问题似乎是 OP 试图在 foreach 循环中修改 List&lt;string&gt; 的内容。

标签: c# list split


【解决方案1】:

尝试使用 LINQ:

var list = new List<string>()
{
    "value a",
    "value b",
    "value 1, value 2, value 3",
    "value c"
};

/* THIS IS THE IMPORTANT PART: */
/* Replace list with kvp.Value */
list = list.SelectMany( 
         i => i.Split( ',' ).Select( v => v.Trim() ) 
       ).ToList();

foreach ( var item in list )
    Console.WriteLine( item );

输出:

值一个
b值
值 1
价值 2
价值 3
值 c

要在您的代码中使用它:

foreach (var kvp in dict)
{
    if (kvp.Key == "STAR-016")
    {
        var newList = 
            kvp.Value.SelectMany(
                i => i.Split( ',' ).Select( v => v.Trim() )
            );
        kvp.Value.Clear();
        kvp.Value.AddRange(newList);
    }
}

感谢@Mudu 指出更简单的i =&gt; 语法

【讨论】:

  • +1 用于使用更优雅的 LINQ。但是,i =&gt; i.Split(',').Select(s =&gt; s.Trim()) 也不行吗? msdn.microsoft.com/en-us/library/b873y76a.aspx
  • 循环通过Dictionary 来查找特定的键值确实没有意义。我的意思是这就是 Dictionary 的字面意义。
  • @juharr - 你可能是对的,但这可能是一个更复杂的循环,我们只看到一个 sn-p。
  • @Cyborgx37:i 是什么?顺便说一句,您不能为 KeyValuePair 赋值,它是只读的。
  • @TimSchmelter - 在复制粘贴中丢失了i =&gt; 部分。您对只读:修改是正确的,尽管您的解决方案显然已经成功了。
【解决方案2】:

假设这只是一个示例,并且您实际上不仅希望键 STAR-016 使用该键,还希望所有值(即 List&lt;string&gt;)包含逗号的位置:

Dictionary<string, List<String>> dict = new Dictionary<string, List<String>>();
dict.Add("STAR-016", new List<string>() { 
    "value a", "value b", "value c", "value 1, value 2, value 3", "value d"
});

foreach (var kvp in dict)
{
    for (int i = kvp.Value.Count - 1; i >= 0; i--)
    {
        string str = kvp.Value[i];
        if (str.Contains(','))
        {
            var parts = str.Split(',').Select(p => p.Trim());
            kvp.Value.RemoveAt(i);
            kvp.Value.InsertRange(i, parts);
        }
    }
}

Demo

我从结尾循环到开头以避免复杂化,因为InsertRange 将添加新字符串,从而增加Count
我正在使用RemoveAt 将带有逗号的字符串替换为添加的新字符串(每个部分由逗号分隔一个)。我使用InsertRange 而不是AddRange 因为你想保持订单。

结果:

value a
value b
value c
value 1
value 2
value 3
value d

【讨论】:

  • 不确定,但看起来 OP 想要删除原始 CSV。
  • @Cyborgx37:但他使用foreach (var a in ar) { kvp.Value.Add(a); } 将零件添加到列表中。请注意,我已经编辑了我的答案,以显示如何用似乎需要的拆分元素替换单个元素。
  • 是的,我同意 - 代码示例显然是错误的。我的评论基于所需的输出。
  • 我觉得你应该考虑从最后倒数。这样您就不会重新处理加工过的物品。
  • @Cyborgx37:你说得对,“回滚”了我的回答 :) 我认为没有必要向后循环,因为我使用的是 InsertRange 而不是 AddRange
【解决方案3】:

您应该可以使用SelectMany 一行代码来做到这一点。

dict["STAR-016"] = dict["STAR-016"].SelectMany(s=>s.Split(',')).ToList();

这会将您的密钥列表替换为以逗号分隔字符串的列表,如果字符串不包含逗号,则它只返回字符串。如果您不希望连续逗号产生空字符串,您也可以考虑使用StringSplitOptions.RemoveEmptyEntries

【讨论】:

  • +1 for SelectMany - 我在想 Scala 的 flatMap,但不知道 SelectMany 是 LINQ 的等价物。
  • +1 如果 OP 不需要遍历字典,这是一个更简单的语法。
  • @Cyborgx37 如果您遍历字典,甚至可以使用它。只需将 'dict["STAR-016"]` 替换为 kvp.Value
  • @juharr:您可能需要考虑使用s.Split(',').Select(p =&gt; p.Trim()),因为所需结果的开头或结尾不包含空格。
【解决方案4】:

您可以使用for 而不是foreach 循环通过List 并修改项目

for (int i = 0; i < kvp.Value.Count; i++)
{
    if (kvp.Value[i].Contains(','))
        ...
}

【讨论】:

  • 我认为有问题的循环不是字典循环,而是 List 循环。
  • OP 希望替换每个列表中包含逗号的单个字符串,并将字符串拆分。所以之后列表可能会增加,但应该删除原始项目。
  • @Cyborgx37 使用 for 而不是 foreach 是解决方案,对于字典和列表也是如此。
  • @TimSchmelter 好吧,OP 在修改 foreach 内的集合时遇到问题。您为 OP 提供了完整的解决方案,我只是向他展示了自己的方法。
  • @VladL:嗯,这甚至​​无法编译,因为密钥是 string。字典的索引器是对键的查找,因此您可以使用dict["STAR-016"],但不能使用dict[0]。字典不是列表。
【解决方案5】:

(编辑:juharr 的 https://stackoverflow.com/a/14875503/17713 与内置 LINQ 功能基本相同,并且功能更强大,在描述实际问题时通常更具表现力)

我会采用yield 的方法,该方法不会修改原始集合。这是一个在 List&lt;string&gt; orig 上运行的示例代码,它也可能在字典中:

public static void Main()
{
    List<string> orig = new List<string>()
    {
        "value a",
        "value b",
        "value c",
        "value 1, value 2, value 3",
        "value d"
    };

    var result = Flatten(orig).ToList();

    foreach(string s in result)
    {
        Console.WriteLine(s);
    }
}

private static IEnumerable<string> Flatten(IList<string> orig)
{
    foreach(string s in orig)
    {
        // split anyway, if there's no colon you just get a one-element
        // array containing s, see
        // http://msdn.microsoft.com/en-us/library/b873y76a.aspx
        foreach(string v in s.Split(','))
        {
            yield return v.Trim();
        }
    }
}

在字典中,您可以将结果替换为原始值:

dict["STAR-016"] = Flatten(dict["STAR-016"]).ToList()

旁注:上面的代码直接找到STAR-016,而不是使用速度较慢的foreach。如果您没有缩短代码,而实际上只是在查找 STAR-016,我建议您使用这种字典查找方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 2021-05-06
    • 1970-01-01
    • 2012-03-05
    相关资源
    最近更新 更多