So sortieren Sie einen IEnumerable <string>

98

Wie kann ich eine IEnumerable<string>alphabetisch sortieren . Ist das möglich?

Bearbeiten: Wie würde ich eine In-Place-Lösung schreiben?

CatZilla
quelle

Antworten:

154

Auf die gleiche Weise würden Sie jede andere Aufzählung sortieren:

var result = myEnumerable.OrderBy(s => s);

oder

var result = from s in myEnumerable
             orderby s
             select s;

oder (Fall ignorieren)

var result = myEnumerable.OrderBy(s => s,
                                  StringComparer.CurrentCultureIgnoreCase);

Beachten Sie, dass wie bei LINQ üblich eine neue IEnumerable <T> erstellt wird, die bei Aufzählung die Elemente der ursprünglichen IEnumerable <T> in sortierter Reihenfolge zurückgibt. Das IEnumerable <T> wird nicht direkt sortiert.


Ein IEnumerable <T> ist schreibgeschützt, dh Sie können nur die Elemente daraus abrufen, aber nicht direkt ändern. Wenn Sie eine Sammlung von Zeichenfolgen direkt sortieren möchten, müssen Sie die ursprüngliche Sammlung sortieren, die IEnumerable <string> implementiert, oder eine IEnumerable <string> zuerst in eine sortierbare Sammlung umwandeln:

List<string> myList = myEnumerable.ToList();
myList.Sort();

Basierend auf Ihrem Kommentar:

_components = (from c in xml.Descendants("component")
               let value = (string)c
               orderby value
               select value
              )
              .Distinct()
              .ToList();

oder

_components = xml.Descendants("component")
                 .Select(c => (string)c)
                 .Distinct()
                 .OrderBy(v => v)
                 .ToList();

oder (wenn Sie später weitere Elemente zur Liste hinzufügen und sortieren möchten)

_components = xml.Descendants("component")
                 .Select(c => (string)c)
                 .Distinct()
                 .ToList();

_components.Add("foo");
_components.Sort();
dtb
quelle
oder myEnumerable.OrderByDescending (s => s).
Grozz
Also, _components = _components.OrderBy (s => s); wäre in Ordnung?
CatZilla
@CatZilla: Das sollte funktionieren, ist aber möglicherweise nicht der beste Weg, um Ihr eigentliches Problem zu lösen. Was ist _components, woher bekommen Sie es, wie verwenden Sie es?
dtb
1
@dtb: Oh, _components wird genau so aus einer XML-Datei gefüllt: _components = (von c in xml.Descendants ("component") wählen Sie c.Value.ToString ()). Distinct (). ToList (); Und ich muss es sortieren.
CatZilla
2
OrderBykehrt zurück IOrderedEnumerable<T>. IOrderedEnumerable<T>leitet sich von IEnumerable<T>so ab, dass es wie verwendet werden kann IEnumerable<T>, aber es erweitert den Typ, der zum Beispiel die Verwendung von ermöglicht ThenBy.
Maciej Hehl
12

Es ist unmöglich, aber es ist nicht.

Grundsätzlich wird jede Sortiermethode Ihre IEnumerablein eine kopieren List, die sortieren Listund Ihnen dann die sortierte Liste zurückgeben, die sowohl eine IEnumerableals auch eine ist IList.

Dies bedeutet, dass Sie die Eigenschaft "unendlich weitermachen" von verlieren IEnumerable, aber dann können Sie eine solche sowieso nicht sortieren.

James Curran
quelle
7
Direkt am. Der Zweck von IEnumerable besteht darin, Ihnen ein Handle für eine Reihe zu präsentieren, die Sie von Anfang bis Ende durchlaufen können, indem Sie weiterhin nach dem "nächsten" Element fragen. Dies bedeutet, dass eine IEnumerable teilweise iteriert werden kann, bevor alle Inhalte bekannt sind. Sie müssen nicht wissen, wann Sie sie alle durchlaufen haben, bis Sie haben. Das Sortieren (wie viele Dinge, die Linq Ihnen ermöglicht) erfordert die Kenntnis der gesamten Serie als geordnete Liste. Der Artikel, der zuerst in einer sortierten Serie erscheint, ist möglicherweise der letzte, der von einer Serie zurückgegeben wird, und Sie werden das nicht wissen, es sei denn, Sie wissen, was alle Artikel sind.
KeithS
8
myEnumerable = myEnumerable.OrderBy(s => s);
Larsenal
quelle
2

Wir können es nicht immer vor Ort tun, aber wir erkennen, wann es möglich ist:

IEnumerable<T> SortInPlaceIfCan(IEnumerable<T> src, IComparer<T> cmp)
{
  List<T> listToSort = (src is List<T>) ? (List<T>)src : new List<T>(src);
  listToSort.Sort(cmp);
  return listToSort;
}
IEnumerable<T> SortInPlaceIfCan(IEnumerable<T> src, Comparison<T> cmp)
{
  return SortInPlaceIfCan(src, new FuncComparer<T>(cmp));
}
IEnumerable<T> SortInPlaceIfCan(IEnumerable<T> src)
{
  return SortInPlaceIfCan(src, Comparer<T>.Default);
}

Dies verwendet die folgende praktische Struktur:

internal struct FuncComparer<T> : IComparer<T>
{
  private readonly Comparison<T> _cmp;
  public FuncComparer(Comparison<T> cmp)
  {
      _cmp = cmp;
  }
  public int Compare(T x, T y)
  {
      return _cmp(x, y);
  }
}
Jon Hanna
quelle
Ich bin mir nicht sicher, ob ich das empfehlen würde. Wenn Sie eine IEnumerable <T> haben, aber den tatsächlichen Typ, der implementiert wird, nicht kennen, sollten Sie ihn wahrscheinlich nicht ändern. Übrigens ist Array.FunctorComparer <T> intern.
dtb
Als ich das, was wir haben, geändert habe, habe ich angenommen, dass dies in der Frage impliziert ist, nach der an Ort und Stelle gesucht wird. dass es es impliziert. Es ist ein Grund, "InPlaceInCan" im Methodennamen zu haben. Methodennamen können in Bezug auf Risiken noch offener sein als die beste Dokumentation;) Ja, Array.FunctorComparer <T> ist intern, aber trivial. Ich habe es eingefügt, weil es der beste Weg ist, den ich mir in einem Beispiel für "Ihren Funktorkomparator, den Sie in Ihren Hilfsklassen haben" vorstellen kann.
Jon Hanna
@dtb auf zweiten Gedanken, geändert, um meine eigenen zu verwenden (warf einen Blick auf Array.FunctorComparer wieder und ich bevorzuge meine trotzdem!)
Jon Hanna
Kluge Idee und Benennung! Aber warum das Double Casting Anti Pattern in listToSort = (src is List<T>) ? (List<T>)src : new List<T>(src);? Wie wäre es damitlistToSort = (src as List<T>); if (null == listToSort) listToSort = new List<T>(src);
Jeroen Wiert Pluimers
1
@JeroenWiertPluimers Es gibt immer auch ein Problem mit Beispielcode. Vielleicht habe ich mich einfach nicht darum gekümmert, weil das oben Genannte etwas kürzer ist und ich mich auf die Sache konzentrieren wollte, aber es ist gut, schlechte Gewohnheiten auch in Beispielen zu entmutigen.
Jon Hanna