2010-05-12 90 views
11

如果我有:转换阵列连接字符串

List<Car> 

其中汽车:

public class Car 
{ 
     public int Year; 
     public string Name; 
} 

,我想利用这个阵列,并创建一个连接字符串“”

所以它会返回:

"Toyota, Ford, Chevy" 

我可以手动像这样做:

private static string CreateConcatenatedList(List<Car> parts_) 
    { 
     StringBuilder b = new StringBuilder(); 
     foreach (Car bp in parts_) 
     { 
      b.Append(bp.Name + ", "); 
     } 
     b.Remove(b.Length - 2, 2); 
     return b.ToString(); 
    } 

,但我认为有可能是一个更优雅的方式

+0

对于大约一百万个解决方案,其中很多都是错误的,对于相关问题,请参阅http://blogs.msdn.com/ericlippert/archive/2009/04/15/comma-quibbling.aspx – 2010-05-12 14:07:12

回答

10
List<Car> cars = //whatever; 
string concat = String.Join(",", cars.Select(c => c.Name).ToArray()); 

编辑:您还可以使用聚合如果你担心创建中间阵列:

string concat = cars.Select(c => c.Name).Aggregate(new StringBuilder(), (sb, current) => 
{ 
    return sb.Length == 0 ? sb.Append(current) : sb.AppendFormat(",{0}", current); 
}).ToString(); 
+0

比我的解决方案还是更快? – leora 2010-05-12 12:33:19

+0

@oo - 它创建了一个效率稍低的中间数组,尽管除非列表中有很多元素,否则您可能不会注意到。你可以使用Aggregate来避免这种情况。 – Lee 2010-05-12 12:44:27

+2

.NET 4.0包含一个string.join重载接受IEnumberable:http://msdn.microsoft.com/en-us/library/dd783876.aspx – Dykam 2010-05-12 13:02:47

5
List<Car> cars = .... 
var result = string.Join(",", cars.Select(car => car.Name).ToArray()); 
+1

的注释。在.NET 4.0中,您不需要'.ToArray()',因为'String.Join'现在具有'IEnumerable '的超载::http://msdn.microsoft.com/en-us/library/dd783876 .aspx – 2010-05-12 12:36:20

1

我认为那是你真正想要的是:

写在你的问题

"Toyota", "Ford", "Chevy" 

"Toyota, Ford, Chevy" 

不能及的。这样就可以实现像这样:

var cars = new List<Car>(); 

var delimitedString = string.Join(", ", cars.Select(c => c.Name).ToArray()); 
+0

你是对的。我已经更新了问题 – leora 2010-05-12 12:38:23

1
ArrayList<Car> cars = ... 
string finalValue = string.Join(",", cars.Select(c => c.Name).ToArray()); 
+0

哈哈哈哈!全部都一样 ;) – 2010-05-12 12:33:37

1

我写了下面extention方法这种类型的案件。它使用一个字符串生成器和Aggregate,而不是string.Join和一个数组,以提高性能。

public static string Concatenate(
    this IEnumerable<string> collection, 
    string separator) 
{ 
    return collection 
     .Skip(1) 
     .Aggregate(
      new StringBuilder().Append(collection.First()), 
      (b, s) => b.Append(separator).Append(s)) 
     .ToString(); 
} 

然后在你的情况下,它只是

cars.Select(c=>Name).Concatenate(", "); 
6

因为你在阅读到答案评论询问是否是快/慢或只是更少的代码。我尝试了一下,并写了一个小的汽车类:

private static Random random = new Random((int)DateTime.Now.Ticks); 
private static string RandomString(int min, int max) 
{ 
    string str = ""; 
    int size = random.Next(min, max + 1); 
    for (int i = 0; i < size; i++) 
     str += Convert.ToChar(Convert.ToInt32(
         Math.Floor(26 * random.NextDouble() + 65))); 
    return str; 
} 

public static void MeassureTicks(int numberCars, int minLength, int maxLength) 
{ 
    // Generate random list 
    List<Car> cars = Enumerable.Range(0, numberCars) 
        .Select(x => new Car(RandomString(
          minLength, maxLength))).ToList(); 

    Stopwatch sw1 = new Stopwatch(), sw2 = new Stopwatch(), 
       sw3 = new Stopwatch(), sw4 = new Stopwatch(); 

    sw1.Start(); 
    string concat1 = CreateConcatenatedList(cars); 
    sw1.Stop(); 
    sw2.Start(); 
    string concat2 = String.Join(",", cars.Select(c => c.Name).ToArray()); 
    sw2.Stop(); 
    sw3.Start(); 
    if (numberCars <= 5000) 
    { 
     string concat3 = cars.Select(c => c.Name).Aggregate("", 
       (str, current) => 
       { 
        return str.Length == 0 ? str = current : 
          str += "," + current; 
       }).ToString(); 
    } 
    sw3.Stop(); 
    sw4.Start(); 
    string concat4 = cars.Select(c => c.Name).Aggregate(
      new StringBuilder(), (sb, current) => 
      { 
       return sb.Length == 0 ? sb.Append(current) : 
         sb.AppendFormat(",{0}", current); 
      }).ToString(); 
    sw4.Stop(); 

    Console.WriteLine(string.Format("{0} car strings joined:\n" + 
       "\tYour method:     {1} ticks\n" + 
       "\tLinq+String.Join:    {2} ticks\n" + 
       "\tLinq+Aggregate+String.Concat: {3} ticks\n" + 
       "\tLinq+Aggregate+StringBuilder: {4} ticks\n", 
       cars.Count, sw1.ElapsedTicks, sw2.ElapsedTicks, 
       numberCars <= 5000 ? sw3.ElapsedTicks.ToString() : "-", 
       sw4.ElapsedTicks)); 

更新:

public class Car 
{ 
    public string Name { get; set; } 
    public Car(string name) { Name = name; } 
} 

长度为5-10的随机生成的字符串测试它 我现在想这两种方法是也在使用聚合。

输出是在我的电脑的一些不同的汽车数量:

5 car strings joined: 
     Your method:     14 ticks 
     Linq+String.Join:    20 ticks 
     Linq+Aggregate+String.Concat: 11 ticks 
     Linq+Aggregate+StringBuilder: 15 ticks 

50 car strings joined: 
     Your method:     50 ticks 
     Linq+String.Join:    45 ticks 
     Linq+Aggregate+String.Concat: 70 ticks 
     Linq+Aggregate+StringBuilder: 73 ticks 

500 car strings joined: 
     Your method:     355 ticks 
     Linq+String.Join:    348 ticks 
     Linq+Aggregate+String.Concat: 5365 ticks 
     Linq+Aggregate+StringBuilder: 619 ticks 

5000 car strings joined: 
     Your method:     3584 ticks 
     Linq+String.Join:    3357 ticks 
     Linq+Aggregate+String.Concat: 379635 ticks 
     Linq+Aggregate+StringBuilder: 6078 ticks 

50000 car strings joined: 
     Your method:     33705 ticks 
     Linq+String.Join:    34082 ticks 
     Linq+Aggregate+String.Concat: - ticks 
     Linq+Aggregate+StringBuilder: 92839 ticks 

500000 car strings joined: 
     Your method:     508439 ticks 
     Linq+String.Join:    376339 ticks 
     Linq+Aggregate+String.Concat: - ticks 
     Linq+Aggregate+StringBuilder: 616048 ticks 

LINQ的+ String.Join方法确实有点快更少的代码。与StringBuilter一起缩放非常好(不像字符串连接),但速度稍慢。因此,要么使用你的方法,要么Linq + String.Join,这是一个很好的线上,也容易阅读。