Comment trier une <chaîne> IEnumerable

98

Comment puis-je trier un IEnumerable<string>fichier par ordre alphabétique. Est-ce possible?

Edit: Comment pourrais-je écrire une solution sur place?

CatZilla
la source

Réponses:

155

De la même manière que vous trieriez n'importe quel autre énumérable:

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

ou

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

ou (sans tenir compte de la casse)

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

Notez que, comme d'habitude avec LINQ, cela crée un nouveau IEnumerable <T> qui, lorsqu'il est énuméré, retourne les éléments du IEnumerable <T> d'origine dans l'ordre trié. Il ne trie pas le IEnumerable <T> sur place.


Un IEnumerable <T> est en lecture seule, c'est-à-dire que vous ne pouvez en récupérer que les éléments, mais ne pouvez pas le modifier directement. Si vous souhaitez trier une collection de chaînes sur place, vous devez d'abord trier la collection d'origine qui implémente IEnumerable <string>, ou transformer une IEnumerable <string> en une collection triable en premier:

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

Sur la base de votre commentaire:

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

ou

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

ou (si vous souhaitez ajouter ultérieurement d'autres éléments à la liste et la conserver triée)

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

_components.Add("foo");
_components.Sort();
dtb
la source
ou myEnumerable.OrderByDescending (s => s).
Grozz le
Donc, _components = _components.OrderBy (s => s); serait bien?
CatZilla
@CatZilla: Cela devrait fonctionner, mais ce n'est peut-être pas le meilleur moyen de résoudre votre problème réel. Qu'est-ce que _components, d'où provient-il, comment l'utilisez-vous?
dtb le
1
@dtb: Oh, _components est rempli à partir d'un fichier XML précisément de cette façon: _components = (de c dans xml.Descendants ("composant") sélectionnez c.Value.ToString ()). Distinct (). ToList (); Et j'ai besoin de le trier.
CatZilla le
2
OrderByrevient IOrderedEnumerable<T>. IOrderedEnumerable<T>dérive de IEnumerable<T>donc il peut être utilisé comme IEnumerable<T>, mais il étend le type, permettant par exemple, l'utilisation de ThenBy.
Maciej Hehl
12

C'est impossible, mais ce n'est pas le cas.

Fondamentalement, toute méthode de tri va copier votre IEnumerabledans un List, trier le Listpuis vous retourner la liste triée, qui est IEnumerableaussi bien un fichier IList.

Cela signifie que vous perdez la propriété "continue infiniment" d'un IEnumerable, mais vous ne pouvez pas en trier une comme ça de toute façon.

James Curran
la source
7
Droit dessus. Le but de IEnumerable est de vous présenter un descripteur d'une série que vous pouvez itérer, du début à la fin, en continuant à demander l'élément "suivant". Cela signifie qu'un IEnumerable peut être partiellement itéré avant que tout le contenu ne soit connu; vous n'avez pas besoin de savoir quand vous les avez tous passés jusqu'à ce que vous l'ayez fait. Le tri (comme beaucoup de choses que Linq vous permet de faire) nécessite la connaissance de la série entière sous forme de liste ordonnée; l'élément qui apparaîtrait en premier dans une série triée peut être le dernier retourné par une série, et vous ne le saurez que si vous savez ce que sont tous les éléments.
KeithS
8
myEnumerable = myEnumerable.OrderBy(s => s);
Larsenal
la source
2

Nous ne pouvons pas toujours le faire sur place, mais nous détectons quand c'est possible:

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

Cela utilise la structure pratique suivante:

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
la source
Je ne sais pas si je recommanderais cela. Si vous avez un IEnumerable <T> mais que vous ne connaissez pas le type réel qui l'implémente, vous ne devriez probablement pas le modifier. Btw, Array.FunctorComparer <T> est interne.
dtb le
En modifiant ce que nous avons, j'ai supposé que cela était impliqué dans la question de la recherche sur place; que cela l’implique. C'est une raison d'avoir "InPlaceInCan" dans le nom de la méthode; Les noms de méthodes peuvent être encore plus francs sur les risques que la meilleure documentation;) Ouais, Array.FunctorComparer <T> est interne, mais c'est trivial. Je l'ai mis parce que c'est le meilleur moyen auquel je pourrais penser dans un exemple pour "votre comparateur de foncteurs que vous avez dans votre ensemble de classes d'assistance".
Jon Hanna
@dtb sur la deuxième réflexion, changé pour utiliser le mien (j'ai jeté un nouveau coup d'œil à Array.FunctorComparer et je préfère le mien de toute façon!)
Jon Hanna
Idée intelligente et dénomination! Mais pourquoi le deux casting de signatures anti dans listToSort = (src is List<T>) ? (List<T>)src : new List<T>(src);? Que diriez-vous de l'avoir commelistToSort = (src as List<T>); if (null == listToSort) listToSort = new List<T>(src);
Jeroen Wiert Pluimers
1
@JeroenWiertPluimers il y a toujours le problème avec le code d'exemple aussi; peut-être que je ne me suis pas dérangé parce que ce qui précède est légèrement plus court et que je voulais me concentrer sur le sujet en cours, mais il est bon de décourager les mauvaises habitudes même dans les exemples.
Jon Hanna