将对象数组转换为连接字符串

时间:2010-05-12 12:29:31

标签: c# arrays

如果我有:

 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();
    }

但我认为可能会有更优雅的方式

6 个答案:

答案 0 :(得分:10)

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

编辑:如果您担心创建中间数组,也可以使用Aggregate:

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

答案 1 :(得分:6)

因为您在对Lees的评论中询问是否更快/更慢或只是更少的代码。我试了一下,写了一个小车类:

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

使用随机生成的长度为5-10的字符串对其进行测试:

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));

<强>更新 我现在正在尝试使用聚合的两种方法。

输出在我的电脑上用于不同数量的汽车:

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,这是一个很好的oneliner,也很容易阅读。

答案 2 :(得分:5)

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

答案 3 :(得分:1)

我认为你真正想要的是:

"Toyota, Ford, Chevy" 

而不是:

"Toyota", "Ford", "Chevy" 

如你的问题所述。这可以这样实现:

var cars = new List<Car>();

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

我为这种情况编写了以下扩展方法。它使用字符串构建器和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(", ");