374

写老派最有效的方法是什么:

StringBuilder sb = new StringBuilder();
if (strings.Count > 0)
{
    foreach (string s in strings)
    {
        sb.Append(s + ", ");
    }
    sb.Remove(sb.Length - 2, 2);
}
return sb.ToString();

...在 LINQ 中?

4

17 回答 17

557

此答案显示了问题中要求的 LINQ ( Aggregate) 的用法,不适合日常使用。因为这不使用 aStringBuilder它对于很长的序列会有可怕的性能。对于常规代码使用String.Join,如另一个答案所示

使用这样的聚合查询:

string[] words = { "one", "two", "three" };
var res = words.Aggregate(
   "", // start with empty string to handle empty list case.
   (current, next) => current + ", " + next);
Console.WriteLine(res);

这输出:

, 一二三

聚合是一个函数,它接受一组值并返回一个标量值。T-SQL 中的示例包括 min、max 和 sum。VB 和 C# 都支持聚合。VB 和 C# 都支持聚合作为扩展方法。使用点表示法,只需调用IEnumerable对象上的方法。

请记住,聚合查询会立即执行。

更多信息 - MSDN:聚合查询


如果您真的想使用CodeMonkeyKing在评论中提出的Aggregate使用变体,这将与常规代码大致相同,包括对大量对象的良好性能:StringBuilderString.Join

 var res = words.Aggregate(
     new StringBuilder(), 
     (current, next) => current.Append(current.Length == 0? "" : ", ").Append(next))
     .ToString();
于 2008-10-20T08:53:13.910 回答
410
return string.Join(", ", strings.ToArray());

在 .Net 4 中,有一个新的重载string.Join接受IEnumerable<string>。代码将如下所示:

return string.Join(", ", strings);
于 2008-10-20T13:28:34.447 回答
132

为什么要使用 Linq?

string[] s = {"foo", "bar", "baz"};
Console.WriteLine(String.Join(", ", s));

IEnumerable<string>据我所知,这非常有效并且可以接受任何内容。Aggregate这里不需要任何慢得多的东西。

于 2008-09-23T18:18:34.477 回答
79

你看过聚合扩展方法吗?

var sa = (new[] { "yabba", "dabba", "doo" }).Aggregate((a,b) => a + "," + b);
于 2008-09-23T18:09:49.740 回答
58

我的代码中的真实示例:

return selected.Select(query => query.Name).Aggregate((a, b) => a + ", " + b);

查询是具有名称属性的对象,该属性是一个字符串,我想要所选列表中所有查询的名称,以逗号分隔。

于 2008-10-20T08:52:59.587 回答
32

Here is the combined Join/Linq approach I settled on after looking at the other answers and the issues addressed in a similar question (namely that Aggregate and Concatenate fail with 0 elements).

string Result = String.Join(",", split.Select(s => s.Name));

or (if s is not a string)

string Result = String.Join(",", split.Select(s => s.ToString()));

  • Simple
  • easy to read and understand
  • works for generic elements
  • allows using objects or object properties
  • handles the case of 0-length elements
  • could be used with additional Linq filtering
  • performs well (at least in my experience)
  • doesn't require (manual) creation of an additional object (e.g. StringBuilder) to implement

And of course Join takes care of the pesky final comma that sometimes sneaks into other approaches (for, foreach), which is why I was looking for a Linq solution in the first place.

于 2012-10-04T19:02:53.463 回答
29

您可以StringBuilder使用Aggregate

  List<string> strings = new List<string>() { "one", "two", "three" };

  StringBuilder sb = strings
    .Select(s => s)
    .Aggregate(new StringBuilder(), (ag, n) => ag.Append(n).Append(", "));

  if (sb.Length > 0) { sb.Remove(sb.Length - 2, 2); }

  Console.WriteLine(sb.ToString());

Select那里只是为了表明你可以做更多的 LINQ 东西。)

于 2010-05-19T20:42:05.397 回答
22

超过 3000 个元素的 StringBuilder 与 Select & Aggregate 案例的快速性能数据:

单元测试 - 持续时间(秒)
LINQ_StringBuilder - 0.0036644
LINQ_Select.Aggregate - 1.8012535

    [TestMethod()]
    public void LINQ_StringBuilder()
    {
        IList<int> ints = new List<int>();
        for (int i = 0; i < 3000;i++ )
        {
            ints.Add(i);
        }
        StringBuilder idString = new StringBuilder();
        foreach (int id in ints)
        {
            idString.Append(id + ", ");
        }
    }
    [TestMethod()]
    public void LINQ_SELECT()
    {
        IList<int> ints = new List<int>();
        for (int i = 0; i < 3000; i++)
        {
            ints.Add(i);
        }
        string ids = ints.Select(query => query.ToString())
                         .Aggregate((a, b) => a + ", " + b);
    }
于 2010-05-10T22:46:43.030 回答
19

我总是使用扩展方法:

public static string JoinAsString<T>(this IEnumerable<T> input, string seperator)
{
    var ar = input.Select(i => i.ToString());
    return string.Join(seperator, ar);
}
于 2009-05-08T17:02:34.813 回答
13

通过“超酷的 LINQ 方式”,您可能是在谈论 LINQ 通过使用扩展方法使函数式编程更容易接受的方式。我的意思是,允许函数以视觉线性方式(一个接一个)而不是嵌套(一个在另一个内部)链接的语法糖。例如:

int totalEven = Enumerable.Sum(Enumerable.Where(myInts, i => i % 2 == 0));

可以这样写:

int totalEven = myInts.Where(i => i % 2 == 0).Sum();

您可以看到第二个示例更易于阅读。您还可以看到如何在减少缩进问题或出现在表达式末尾的Lispy闭合括号的情况下添加更多函数。

许多其他答案表明这String.Join是要走的路,因为它是最快或最容易阅读的。但是,如果您接受我对“超酷 LINQ 方式”的解释,那么答案是使用String.Join但将其包装在 LINQ 样式扩展方法中,这将允许您以视觉上令人愉悦的方式链接您的函数。所以如果你想写sa.Concatenate(", "),你只需要创建这样的东西:

public static class EnumerableStringExtensions
{
   public static string Concatenate(this IEnumerable<string> strings, string separator)
   {
      return String.Join(separator, strings);
   }
}

这将提供与直接调用一样高性能的代码(至少在算法复杂性方面),并且在某些情况下可能使代码更具可读性(取决于上下文),特别是如果块中的其他代码使用链式函数样式.

于 2012-05-16T12:37:37.140 回答
5

在上一个问题上有各种替代答案- 诚然,它以整数数组作为源,但收到了普遍的答案。

于 2008-10-20T09:14:32.680 回答
5

这里它使用纯 LINQ 作为单个表达式:

static string StringJoin(string sep, IEnumerable<string> strings) {
  return strings
    .Skip(1)
    .Aggregate(
       new StringBuilder().Append(strings.FirstOrDefault() ?? ""), 
       (sb, x) => sb.Append(sep).Append(x));
}

而且它非常快!

于 2012-09-03T04:34:09.773 回答
3

我将稍微作弊并抛出一个新的答案,似乎总结了这里最好的一切,而不是将其粘贴在评论中。

所以你可以这样写:

List<string> strings = new List<string>() { "one", "two", "three" };

string concat = strings        
    .Aggregate(new StringBuilder("\a"), 
                    (current, next) => current.Append(", ").Append(next))
    .ToString()
    .Replace("\a, ",string.Empty); 

编辑:您要么先检查一个空的可枚举,要么.Replace("\a",string.Empty);在表达式的末尾添加一个。我想我可能一直试图变得有点太聪明了。

@a.friend 的答案可能会稍微好一点,我不确定 Replace 与 Remove 相比在幕后做了什么。如果出于某种原因您想连接以 \a 结尾的字符串,那么唯一的另一个警告是您会丢失分隔符......我发现这不太可能。如果是这种情况,您确实有其他花哨的角色可供选择。

于 2011-09-01T17:42:52.357 回答
2

您可以将 LINQ 和string.join()相当有效的结合起来。在这里,我从字符串中删除一个项目。也有更好的方法来做到这一点,但这里是:

filterset = String.Join(",",
                        filterset.Split(',')
                                 .Where(f => mycomplicatedMatch(f,paramToMatch))
                       );
于 2011-02-02T09:00:14.363 回答
1

这里有很多选择。您可以使用 LINQ 和 StringBuilder 来获得性能,如下所示:

StringBuilder builder = new StringBuilder();
List<string> MyList = new List<string>() {"one","two","three"};

MyList.ForEach(w => builder.Append(builder.Length > 0 ? ", " + w : w));
return builder.ToString();
于 2010-04-21T20:02:07.253 回答
1

在使用 linq 解析 IIS 日志文件时,我做了以下快速而肮脏的操作,它在 100 万行(15 秒)时工作得很好,尽管在尝试 200 万行时出现内存不足错误。

    static void Main(string[] args)
    {

        Debug.WriteLine(DateTime.Now.ToString() + " entering main");

        // USED THIS DOS COMMAND TO GET ALL THE DAILY FILES INTO A SINGLE FILE: copy *.log target.log 
        string[] lines = File.ReadAllLines(@"C:\Log File Analysis\12-8 E5.log");

        Debug.WriteLine(lines.Count().ToString());

        string[] a = lines.Where(x => !x.StartsWith("#Software:") &&
                                      !x.StartsWith("#Version:") &&
                                      !x.StartsWith("#Date:") &&
                                      !x.StartsWith("#Fields:") &&
                                      !x.Contains("_vti_") &&
                                      !x.Contains("/c$") &&
                                      !x.Contains("/favicon.ico") &&
                                      !x.Contains("/ - 80")
                                 ).ToArray();

        Debug.WriteLine(a.Count().ToString());

        string[] b = a
                    .Select(l => l.Split(' '))
                    .Select(words => string.Join(",", words))
                    .ToArray()
                    ;

        System.IO.File.WriteAllLines(@"C:\Log File Analysis\12-8 E5.csv", b);

        Debug.WriteLine(DateTime.Now.ToString() + " leaving main");

    }

我使用 linq 的真正原因是我之前需要的 Distinct():

string[] b = a
    .Select(l => l.Split(' '))
    .Where(l => l.Length > 11)
    .Select(words => string.Format("{0},{1}",
        words[6].ToUpper(), // virtual dir / service
        words[10]) // client ip
    ).Distinct().ToArray()
    ;
于 2011-12-14T18:41:55.440 回答
0

不久前我在博客上写过这个,我所做的接缝正是你正在寻找的:

http://ondevelopment.blogspot.com/2009/02/string-concatenation-made-easy.html

在博客文章中描述了如何实现适用于 IEnumerable 并命名为 Concatenate 的扩展方法,这将让您编写如下内容:

var sequence = new string[] { "foo", "bar" };
string result = sequence.Concatenate();

或者更复杂的事情,比如:

var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name);
string result = methodNames.Concatenate(", ");
于 2009-11-15T11:50:30.957 回答