将IEnumerable<string>转换为字符串

14

考虑以下内容:

string test = "";
somestring.ToList().Take(50).Select(
    delegate(char x)
    {
        test += x;
        return x;
    }
);
为什么在此之后 test 是空的?实际上我不关心它的返回值(我知道它是 IEnumerable<string>)。
如果这一切看起来很混乱,那么我该如何将由 Select() 返回的 IEnumerable<char> 转换为 string
5个回答

22

因为您没有执行查询。Linq是惰性的。只有在执行foreachToList/ToArray/ToDictionary时才会执行它。

我建议这样做。

string test = new string(somestring.Take(50).ToArray());
或者甚至使用

string test = somestring.Substring(0, 50);

更多内容请见。 Select 旨在将某种转换应用于序列中的每个元素。此操作也称为 map。如果您想从序列中产生单个元素,则使用 Aggregate,又称为 reduce。它不是延迟执行的,而是强制执行查询。


“Remove”?我想你是指“Substring”吧? - Timwi
@Greg Linq是一种声明式框架。对于习惯命令式编程的开发者来说,这可能是一些令人惊讶的东西。 - Andrey
如果somestring的类型是IEnumberable<string>,则此代码将无法编译。字符串类没有重载的构造函数可以接受一个字符串数组作为参数。 - Dirk Vollmar
@0xA3 你说得对又不对。它会编译通过,因为我传递的是 char[] 而不是 string[]。在第二种情况下,它将无法编译。 - Andrey
是的,当然。在我写评论时,问题是关于 IEnumerable<string> 的,因此我假设 somestring 是该类型。 - Dirk Vollmar
显示剩余2条评论

16

(其他人已经解释了为什么它不起作用。)

您的问题目前并不十分清晰 - 您是否实际上正在处理一个 IEnumerable<char> 还是一个 IEnumerable<string> 不清楚。(您的文本提示是 IEnumerable<string>;您的代码提示是 IEnumerable<char>)。如果这是一个 IEnumerable<string> 并且您正在使用 .NET 4,那么就非常容易:

string combined = string.Join("", list.Take(50));

如果你正在使用 .NET 3.5,那么很容易:

string combined = string.Join("", list.Take(50).ToArray());

如果您想在字符串之间使用分隔符,请明显地使用像","这样的内容。

如果您正在处理通用的IEnumerable<char>,那么请使用

string combined = new string(chars.Take(50).ToArray());

如果你的起点是一个字符串(string),那么使用Substring函数就可以了 :)


他遍历字符串时,请参阅“delegate(char x)”。我认为在IEnumberable的字符上执行string.Join不是很有效率。 - Andrey
@Andrey:我基于他试图连接 IEnumerable<string> 而不是 IEnumerable<char> 的声明来回答问题... 基本上这个问题目前有问题。我已经进行了编辑以表明这一点。 - Jon Skeet
是的,我指的是IEnumerable<char>而不是string,那是一个打字错误,抱歉。 - Stacker
2
“” over string.Empty?去烫你的手吧 :P - annakata
@Stacker:好的,那就改变策略——采用底部方法(Timwi也建议过)。 - Jon Skeet
1
@annakata:我在其他地方解释过为什么我更喜欢使用""而不是string.Empty——我觉得它更易读。 - Jon Skeet

3

Select返回一个IEnumerable<char>,但是你的代码中没有枚举它,所以委托将不会被执行。如果你将它改为:

string test = "";
somestring.Take(50).Select(
    delegate(char x)
    {
        test += x;
        return x;
    }
).ToList();

3
因为您仅声明了该序列,但从未执行它。如果您在末尾添加另一个 .ToList(),那么 test 将包含其中的字符。
然而,我强烈反对这种做法。您正在使用序列的求值来引起副作用。您已经发现结果很令人困惑。如果您只想要序列的前50个项目,请使用单独的 Take
var partSequence = fullSequence.Take(50);

你上面的例子可以写成这样:

var partString = new string(someString.Take(50).ToArray());

但我相信你已经知道为此可以使用string.Substring()函数。


2

由于 Select 是惰性求值,因此您传递的函数只有在使用 Select 的结果时才会被评估。

通常情况下,对于Select来说使用带有副作用的函数是不好的想法。您应该改用 foreach。

在这种特殊情况下,您可以直接使用 String.Join 方法。


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