Linq lambda foreach

4
尝试将每个字符串包装在数组中,但它不起作用,意味着foreach循环,请解释为什么。
string s = "keepsakes,table runners,outdoor accessories";
List<string> keys = s.Split(',').ToList();
keys.ForEach(x => x = String.Concat("%", x, "%"));
s = String.Join(",", keys);
Console.WriteLine(s); 

需要获取 "%纪念品%,%桌布%,%户外配件%"

更新: 非常感谢建议(它是同样的方式)

但是有人能回答为什么在下面这个位置它起作用而不起作用吗:

对象

    public class MyItems
    {
        public string Item { get; set; }
    }

和函数

        string s = "keepsakes,table runners,outdoor accessories";
        List<MyItems> keys = s.Split(',').ToList().Select(x => new MyItems(){ Item = x }).ToList();
        keys.ForEach(x => x.Item = String.Concat("%", x.Item, "%"));
        s = String.Join(",", keys.Select(x => x.Item).ToList());
        Console.WriteLine(s);

1
"它不起作用" - 准确发生了什么?实际输出是什么?此外,“数组”是什么意思? - O. R. Mapper
我更新了我的答案,请查看。 - codingadventures
8个回答

10

您没有在 ForEach 中修改列表,而是只创建字符串并将其分配给本地变量 x,然后将其丢弃。您可以使用 for 循环:

for(int i = 0; i < keys.Count; i++)
{
    keys[i] = String.Concat("%", keys[i], "%");
}

说实话,这里有一个更简短的LINQ版本,它也规避了核心问题:

s = string.Join(",", s.Split(',').Select(str => "%" + str + "%"));

1
仅返回翻译后的文本:只有答案,不解释! - Kamil Budziewski
请注意更新的答案,如果您可以的话。 - AleksP
除此之外,第二个代码片段可以正常工作,所以我不明白为什么在...下面“有人能回答为什么这个代码可以正常工作而另一个却不能吗?” - Tim Schmelter
1
如果你不理解为什么使用你的类属性能正常运行,原因在于MyItems类是引用类型,而你正在修改 List.ForEach 中每个引用的属性。这样可以修改列表中的原始对象,与你第一个尝试替换引用本身的方法不同。 - Tim Schmelter

4
你可以使用 Join Select Format
string s = "keepsakes,table runners,outdoor accessories";

var output = string.Join(",", s.Split(',').Select(x => string.Format("%{0}%", x)));

请注意更新的答案,如果您可以的话。 - AleksP
1
@DaveBish:你的更新是不正确的。第二个片段与第一个相反,我猜OP想知道为什么。原因与字符串的不可变性无关,而是因为他更改了引用类型的属性,而不是尝试在List.ForEach中替换整个引用。 - Tim Schmelter

3

你可以更简单地处理:将每个逗号替换为%,%

string s = "keepsakes,table runners,outdoor accessories";
string s2 = "%" + s.Replace("," , "%,%") + "%";

请注意更新的答案,如果您可以的话。 - AleksP

2

另一种方法可以使用正则表达式而不是LINQ:

string s = "keepsakes,table runners,outdoor accessories";
string pattern = "\\,+";
string replacement = "%,";

Regex rgx = new Regex(pattern);
string result = string.Format("%{0}%", rgx.Replace(s, replacement));

编辑:

使用类来分配字符串的原因是,当您在第一次实例中使用foreach时,它可以将每个字符串分配给该类的属性,并且可以在下一个实例中使用该类的属性以便更好地管理和处理这些字符串。

keys.ForEach(x => x = String.Concat("%", x, "%"));

x是一个字符串类型的键元素,通过值传递给ForEach函数。以下是一个例子:

var myString = "I'm a string";

Console.WriteLine(myString);

ChangeValue(myString);

Console.WriteLine(myString);

void ChangeValue(string s)
{
    s = "something else";
}

如果您运行该代码片段,您会发现 myString 在方法 ChangeValue 中不会被更改,因为我们试图替换引用。同样的事情也会发生在方法 ForEach 中,这是您不能在 ForEach 中更改列表值的主要原因。
相反,如果您执行以下操作:
class MyClass{
    public string aString;
 }

void ChangeValue(MyClass s)
{
    s.aString = "something else";
}

 var myClass = new MyClass();
 myClass.aString =  "I'm a string";

 Console.WriteLine(myClass.aString);

 ChangeValue(myClass);

 Console.WriteLine(myClass.aString);

您必须意识到,在第二个 Console.WriteLine 中,字段 aString 的值将会被改变为 "something else"。 这里 有一个很好的解释,说明引用类型是如何按值传递的。


请注意更新的答案,如果您可以的话。 - AleksP

2

另一种方法(不使用lambda表达式):

string result = string.Concat("%", s, "%").Replace(",", "%,%");

请注意更新的答案,如果您可以的话。 - AleksP

1
ForEach 不会改变你的字符串列表,它只会对每个字符串执行一个操作。相反,你可以这样做:
string s = "keepsakes,table runners,outdoor accessories";
List<string> keys = s.Split(',').Select(x => String.Concat("%", x, "%")).ToList();
s = String.Join(",", keys);
Console.WriteLine(s);

请注意更新的答案,如果您可以的话。 - AleksP

1

List<>.ForEach无法用于更改列表的内容。您可以创建一个新列表或使用for循环。

keys = keys.Select(x => "%" + x + "%").ToList();

或者

for(int i = 0; i < keys.Count; i++)
{
    keys[i] = "%" + keys[i] + "%";
}

1

正如其他人所指出的那样,传递给 List.ForEach 的 lambda 表达式不返回值。

LINQ 是惰性求值的,但 String.Join 会强制枚举:

var res = String.Join(",", input.Split(',').Select(s => "%" + s + "%"));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接