2013-07-18 24 views
7

W języku C# wywołanie metody .Split spowoduje podzielenie łańcucha na tablicę łańcuchów na podstawie niektórych znaków lub ciągów znaków.Czy istnieje metoda "podzielonej listy" w języku C#?

Czy istnieje odpowiednia metoda dla list lub tablic?

Na przykład:

var foo = new List<int>() { 1, 2, 3, 0, 4, 5, 0, 6 }; 
var output = Split(foo, 0); 
// produces { { 1, 2, 3 }, { 4, 5 }, { 6 } } 

To, co mam tak daleko - jest tam czystsze lub bardziej wymowny sposób realizacji tego samego zadania?

IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> list, T divider) 
{ 
    var output = new List<List<T>>(); 
    var temp = new List<T>(); 
    foreach (var item in list) 
    { 
     if (item.Equals(divider)) 
     { 
      output.Add(temp); 
      temp = new List<T>(); 
     } 
     else 
     { 
      temp.Add(item); 
     } 
    } 

    output.Add(temp); 
    return output; 
} 

Edit:

To właśnie przyszło mi do głowy, że moja wersja będzie podzielić listę tylko jednego elementu, natomiast string.Split można podzielić przy użyciu pojedynczego znaku, lub dowolny ciąg znaków.

Tylko w celu zapewnienia kompletności, jaki byłby najlepszy sposób realizacji tego?

+1

Możesz być w stanie coś zrobić z IndexOf, choć nie jestem pewien, jak to porównuje równości w ogóle ... – Jeff

+0

Na Edycja - podczas gdy z pojedynczym separatorem jest całkiem prosto do przodu, co jest "dobrym/lepszym" kodem, nie jest tak w przypadku pasujących sekwencji: trzeba poprawnie radzić sobie z brakami podczas dopasowywania ("aabbaba" podzielone na 'bab' wymaga jakiejś formy ponownego przejrzenia pierwszego' b' do zwróć go) z różnymi kompromisami w wielu podejściach, aby to zrobić. Istnieje również wiele różnych algorytmów dopasowywania ciągów (dokładnie to, co chcesz w swojej edycji), które optymalizują dla różnych kryteriów. Więc edycja nie jest tak naprawdę odpowiedzialna (w sensie "najlepszego"). –

+0

możliwy duplikat [Grupy po elemencie w Linq] (http://stackoverflow.com/questions/3759123/group-by-element-in-linq) – nawfal

Odpowiedz

8

Brak wbudowanej odpowiednik, ale leniwy ocenie jeden byłby

IEnumerable<IEnumerable<T>> Split<T>(IEnumerable<T> list, T divider) 
{ 
    var temp = new List<T>(); 
    foreach (var item in list) 
    { 
     if (!item.Equals(divider)) 
     { 
      temp.Add(item); 
     } 
     else 
     { 
      yield return temp; 
      temp = new List<T>(); 
     } 
    } 

    if(temp.Count>0) yield return temp; 
} 
2

Nie istnieje żaden specjalny sposób istniejące w ramach o podzieleniu sekwencję.

Kod jest uzasadniony.

Trasy poprawić/zmienić:

  • Możesz być w stanie wykorzystać yield return zamiast dodawania do output zdobyć leniwy oceny.
  • Przy jeszcze bardziej interesującym kodzie można również tworzyć leniwy list (co może być ważne, jeśli sekwencja wejściowa nie jest związana/zbyt długie segmenty).
  • I można za pomocą Aggregate jeśli chcesz pokazać jeden kod oświadczenie ...
0

Nie znam żadnego wbudowanej funkcji. Jednak uważam ten sposób:

public static IEnumerable<List<int>> Split(List<int> list, int delimiter) 
{ 
    var start = 0; 
    foreach (var end in list.FindAll(x => x == delimiter).Select(splitter => list.IndexOf(splitter, start))) 
    { 
     yield return list.GetRange(start, end - start); 

     start = end + 1; 
    } 

    if (start <= list.Count) 
    { 
     yield return list.GetRange(start, list.Count - start); 
    } 
} 
+0

Nie jestem pewien, czy to naprawdę jest lepsze od metody Op ... może być bardziej czytelny, ale wymaga również (?) wielokrotnych przejść przez dane wejściowe. – McGarnagle

+0

I nie zadziała, jeśli 'list' jest' IEnumerable 'not' List '(z powodu * GetRange *) – I4V

Powiązane problemy