2010-05-12 10 views
11

jeśli mam:nawrócony Tablica obiektów do połączonego łańcucha

List<Car> 

gdzie samochód jest:

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

i chcę wykorzystać tę tablicę i stworzyć łączone smyczkowych „”

, więc powróci:

"Toyota, Ford, Chevy" 

mogę zrobić to ręcznie tak:

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

ale pomyślałem, że może być bardziej elegancki sposób

+0

Za około milion rozwiązań, z których wiele jest błędnych, do pokrewnego problemu patrz komentarze do strony http://blogs.msdn.com/ericlippert/archive/2009/04/15/comma-quibbling.aspx –

Odpowiedz

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

EDIT: można też użyć Agregat jeśli martwisz się o tworzeniu pośredniego tablica:

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

jest to szybsze od mojego rozwiązania lub po prostu mniej kodu? – leora

+0

@oo - Tworzy pośrednią tablicę, która jest trochę nieefektywna, chociaż prawdopodobnie nie zauważysz, chyba że masz dużo elementów na liście. Możesz użyć Aggregate, aby tego uniknąć. – Lee

+2

.NET 4.0 zawiera string.join overload akceptujący IEnumberable: http://msdn.microsoft.com/en-us/library/dd783876.aspx – Dykam

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

. że w .NET 4.0 nie potrzebujesz '.ToArray()', ponieważ 'String.Join' ma teraz przeciążenie z' IEnumerable ': http://msdn.microsoft.com/en-us/library/dd783876 .aspx –

1

myślę, że to, co naprawdę chcesz to:

"Toyota, Ford, Chevy" 

a nie:

"Toyota", "Ford", "Chevy" 

jak napisał w swoim pytaniu. Można to osiągnąć w taki sposób:

var cars = new List<Car>(); 

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

masz rację. Mam zaktualizowane pytanie – leora

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

Ha ha ha ha! Wszystkie takie same ;) –

1

napisałem następujący sposób przedłużeniem tego typu sprawy. Używa konstruktora ciągów i Aggregate zamiast string.Join i tablica dla niewielkiej poprawy wydajności.

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

Następnie w Twoim przypadku jest to po prostu

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

Ponieważ poprosiłeś w komentarzu do osadu odpowiedź czy jest szybsze/wolniejsze lub po prostu mniej kodu. Próbowałem trochę i napisał małą klasę samochodu:

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

testowałem go z losowo generowanych ciągów o długości 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)); 

Aktualizacja: Jestem teraz próbuje obu metod, które również używają agregatu.

Wyjścia są na moim komputerze z jakiegoś innego liczby samochodów:

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 metoda jest rzeczywiście nieco szybciej i mniej kodu. Agregacja razem z skalą StringBuilter jest bardzo dobra (nie przypomina konkatenacji łańcuchów), ale jest nieco wolniejsza. Tak więc albo użyj swojej metody, albo Linq + String.Join, która jest ładnym onelinerem, a także łatwo czytelna.

Powiązane problemy