2010-06-29 9 views
6

Jeśli mam na przykład następujący ciąg:wpakować rozdzielany ciąg do listy <int>

"123; 3344; 4334; 12"

i chcę te numery w ogólnej List<int>, chyba nie znam dobrej drogi tutaj, poza dzieleniem w pętli i konwersją, a następnie dodawaniem do List<int> przez każdą iterację. Czy ktoś ma na to inne sposoby?

Zaktualizowano. Oto, co wymyśliłem. Chcę to zrobić w starym stylu, nie w LINQ, ponieważ staram się poprawić tylko z łańcuchami, tablicami, listami i manipulowaniem i konwersją w ogóle.

public List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    List<int> list = new List<int>(); 

    if (string.IsNullOrEmpty(stringToSplit)) 
     return list; 

    string[] values = stringToSplit.Split(splitDelimiter); 

    if (values.Length <= 1) 
     return list; 

    foreach (string s in values) 
    { 
     int i; 
     if (Int32.TryParse(s, out i)) 
      list.Add(i); 
    } 

    return list; 
} 

Jest to nowa metoda narzędzie Ciąg I planujesz używać ilekroć muszę konwertować listę ciąg rozdzielany do listy

Więc wracam pustą listę z powrotem do osoby dzwoniącej, jeśli coś się nie powiedzie. Dobry zły? czy to dość powszechne?

Tak, jest więcej "eleganckich" sposobów na zrobienie tego za pomocą LINQ, ale chcę zrobić to ręcznie. Stara droga na razie tylko dla własnego zrozumienia.

Ponadto, co przeszkadza mi o to:

list.AddRange(str.Split(';').Select(Int32.Parse)); 

jest to, że nie mam pojęcia:

  1. Jak wpakować w TryParse tam zamiast.
  2. Co się stanie, jeśli str.Split(';').Select(Int32.Parse) po prostu zawiedzie z jakiegokolwiek powodu ... wtedy metoda, w której znajduje się ten AddRange, wysadzi się w powietrze i jeśli nie dodaję try/catch dookoła tej całej rzeczy, jestem spieprzony, jeśli nie postępuj właściwie.
+0

Korzystanie TryParse tutaj jest poważnym błędem: http://en.wikipedia.org/wiki/GIGO –

Odpowiedz

5
string str = "123;3344;4334;12"; 
List<int> list = new List<int>(); 

foreach (string s in str.Split(';')) 
{ 
    list.Add(Int32.Parse(s)); 
} 
+1

+1, można przeczytać tytuł! Proponuję użyć TryParse zamiast Parse. –

+0

I raner jeśli możesz po prostu listę List = "123; 3344; 4334; 12" .Split (";"); Wiem, że możesz za pomocą tablicy: string [] list = "123; 3344; 4334; 12" .Split (";"); – PositiveGuy

+1

@ coffe, nie. Nie można niejawnie przekonwertować z tablicy łańcuchów na 'List '. Powinien też być "Split ("; ') '. Zwróć uwagę na pojedynczy cytat, ponieważ jest to literał literowy. –

3
List<int> list = (from numString in "123;3344;4334;12".Split(';') 
        select int.Parse(numString)).ToList(); 
6
static int? ToInt32OrNull(string s) 
{ 
    int value; 
    return (Int32.TryParse(s, out value)) ? value : default(int?);  
} 
// ... 
var str = "123;3344;4334;12"; 
var list = new List<int>(); 
list.AddRange(str.Split(';') 
       .Select(ToInt32OrNull) 
       .Where(i => i != null) 
       .Cast<int>()); 

PYTAJĄCY zauważa:

nie wiem o dobrym sposobem tutaj inny niż podzielić w pętli i zrobić konwersję następnie dodać do listy

Zasadniczo jest to główny powód, dla którego LINQ został wprowadzony do języka C# - przesuń potrzebę pracy z sekwencjami wartości poprzez implementację pętli, a zamiast tego po prostu zadeklaruj zamiar transformacji sekwencji. Jeśli kiedykolwiek pomyślisz "nie wiem jak to zrobić, z wyjątkiem pętli" - czas spojrzeć na konstrukcję LINQ, która wykona pracę za ciebie.

Wydajność Aktualizacja:

Wydajność LINQ został stawiła poniżej. Podczas gdy w komentarzach idea LINQ jest wolniejsza jest broniona, ponieważ uzyskujemy korzyści z czytelności, łatwości konserwacji i kompozycyjności, jest jeszcze jeden aspekt, który daje LINQ łatwą przewagę wydajnościową: równoległość. Oto przykład, w którym dodanie tylko jednego wywołania metody rozszerzeń podwaja wydajność. Jest to świetny przykład, w którym skalowanie eliminuje mikrooptymalizację, nie wymagając nawet bardzo dokładnego pomiaru.Uwaga Nie twierdzę, że mikro-optymalizacje nie są nigdy potrzebne, ale dzięki narzędziom, które mamy dostępne na tym poziomie absrakcji, potrzeba staje się znikoma.

class Program 
{ 
    private const int ElementCount = 10000000; 

    static void Main(string[] args) 
    { 
     var str = generateString(); 
     var stopwatch = new Stopwatch(); 

     var list1 = new List<int>(ElementCount); 
     var list2 = new List<int>(ElementCount); 

     var split = str.Split(';'); 

     stopwatch.Start(); 
     list1.AddRange(split 
          .Select(ToInt32OrNull) 
          .Where(i => i != null) 
          .Cast<int>()); 
     stopwatch.Stop(); 

     TimeSpan nonParallel = stopwatch.Elapsed; 

     stopwatch.Restart(); 

     list2.AddRange(split 
          .AsParallel() 
          .Select(ToInt32OrNull) 
          .Where(i => i != null) 
          .Cast<int>()); 

     stopwatch.Stop(); 

     TimeSpan parallel = stopwatch.Elapsed; 

     Debug.WriteLine("Non-parallel: {0}", nonParallel); 
     Debug.WriteLine("Parallel: {0}", parallel); 
    } 

    private static String generateString() 
    { 
     var builder = new StringBuilder(1048576); 
     var rnd = new Random(); 

     for (int i = 0; i < ElementCount; i++) 
     { 
      builder.Append(rnd.Next(99999)); 
      builder.Append(';'); 
     } 

     builder.Length--; 

     return builder.ToString(); 
    } 

    static int? ToInt32OrNull(string s) 
    { 
     int value; 
     return (Int32.TryParse(s, out value)) ? value : default(int?); 
    } 
} 

nierównoległych: 00: 00: 07,0719911

równoległy: 00: 00: 04,5933906

+0

Tak, zastanawiam się nad wydajnością w porównaniu do standardowego podziału w pętli – PositiveGuy

+0

@coffeeaddict: To prawie zawsze pomijalne, i powinno być brane pod uwagę tylko w przypadku zmiany i znalezienia być dobrym problemem, oto dobre, niedawne porównanie: http://jerrytech.blogspot.com/2010/02/revisiting-c-loop-performance.html – codekaizen

+0

Nie wiem, zawsze tu mogę przecenić LINQ również w tym może on zacząć być peformance hog. Nie mówiąc, że jesteś w błędzie ... tak – PositiveGuy

1
string myString = "123;3344;4334;12"; 
var ints = new List<int>(); 
(from s in myString.Split(';') 
select int.Parse()).ToList().ForEach(i=>ints.Add(i)); 

Słyszałem .Net 4.0 może być dodany do ForEachEnumerable<T>, więc ToList może być niepotrzebny (nie można przetestować).

+0

Po 'ToList', masz * listę ints. 'ForEach' jest niepotrzebny. –

+0

@Matthew Flaschen, zgodził się. Moja początkowa (i wprawdzie spiesznie) początkowa myśl była taka, że ​​lista może nie być oryginalna, a jej zawartość może wymagać zachowania. tj. dołącz wyniki do istniejącej listy bez wymiany. –

-1

Myślę, że to najprostszy

var str = "123;3344;4334;12"; 
    var list = str.Split(';').ToList().Cast<int>(); 
+0

-1: To nigdy nie działa, ponieważ nie można rzutować łańcucha na liczbę całkowitą. Możesz go tylko analizować (używając 'int.Parse()' lub 'int.TryParse()'). – Oliver

Powiązane problemy