Tri des éléments en C#

alors j'ai rencontré un problème intéressant aujourd'hui. Nous avons un service web de la WCF qui retourne un IList. Pas grand chose jusqu'à ce que je veuille arranger ça.

S'avère que l'interface IList n'a pas une méthode de tri intégrée.

j'ai fini par utiliser la méthode ArrayList.Adapter(list).Sort(new MyComparer()) pour résoudre le problème mais ça me semblait un peu" ghetto".

j'ai joué avec l'écriture d'une méthode d'extension, également avec l'héritage de IList et mettre en œuvre ma propre méthode de Sort() ainsi que le casting à une liste mais aucun de ceux-ci ne semblait trop élégant.

ainsi ma question Est, est-ce que quelqu'un a une solution élégante pour trier un IList

74
demandé sur lomaxx 2008-08-19 05:23:04

14 réponses

Que Diriez-vous D'utiliser LINQ pour trier des objets pour vous?

dites que vous avez un IList<Car> , et la voiture avait un Engine propriété, je crois que vous pourriez trier comme suit:

from c in list
orderby c.Engine
select c;

Edit: Vous avez besoin d'être rapide pour obtenir des réponses ici. Comme j'ai présenté une syntaxe légèrement différente des autres réponses, je vais laisser ma réponse - cependant, les autres réponses présentées sont également valables.

52
répondu Brad Leach 2008-08-19 01:41:02

vous pouvez utiliser LINQ:

using System.Linq;

IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();
58
répondu Mark Cidade 2008-08-19 01:34:07

cette question m'a inspiré pour écrire un billet de blog: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way /

je pense que, idéalement, le .net Framework inclurait une méthode de tri statique qui accepte un IList, mais la meilleure chose suivante est de créer votre propre méthode d'extension. Il n'est pas trop difficile de créer quelques méthodes qui vous permettront de trier un IList comme vous le feriez pour une liste. En prime, vous pouvez surcharger la méthode D'extension LINQ OrderBy utilisant la même technique, de sorte que si vous utilisez List.Trier, IList.De tri ou de IEnumerable.OrderBy, vous pouvez utiliser la même syntaxe.

public static class SortExtensions
{
    //  Sorts an IList<T> in place.
    public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
    {
        ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison));
    }

    // Convenience method on IEnumerable<T> to allow passing of a
    // Comparison<T> delegate to the OrderBy method.
    public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
    {
        return list.OrderBy(t => t, new ComparisonComparer<T>(comparison));
    }
}

// Wraps a generic Comparison<T> delegate in an IComparer to make it easy
// to use a lambda expression for methods that take an IComparer or IComparer<T>
public class ComparisonComparer<T> : IComparer<T>, IComparer
{
    private readonly Comparison<T> _comparison;

    public ComparisonComparer(Comparison<T> comparison)
    {
        _comparison = comparison;
    }

    public int Compare(T x, T y)
    {
        return _comparison(x, y);
    }

    public int Compare(object o1, object o2)
    {
        return _comparison((T)o1, (T)o2);
    }
}

avec ces extensions, triez votre liste comme vous le feriez une liste:

IList<string> iList = new []
{
    "Carlton", "Alison", "Bob", "Eric", "David"
};

// Use the custom extensions:

// Sort in-place, by string length
iList.Sort((s1, s2) => s1.Length.CompareTo(s2.Length));

// Or use OrderBy()
IEnumerable<string> ordered = iList.OrderBy((s1, s2) => s1.Length.CompareTo(s2.Length));

il y a plus d'infos dans le post: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way /

52
répondu David Mills 2011-02-18 15:39:47

vous allez devoir faire quelque chose comme ça je pense (le transformer en un type plus concret).

peut-être le prendre dans une liste de T plutôt que ArrayList, de sorte que vous obtenez la sécurité de type et plus d'options pour la façon dont vous mettez en œuvre le compareur.

9
répondu Leon Bambrick 2008-08-19 01:29:10

la réponse acceptée par @DavidMills est assez bonne, mais je pense qu'elle peut être améliorée. D'une part, il n'est pas nécessaire de définir la classe ComparisonComparer<T> lorsque le cadre comprend déjà une méthode statique Comparer<T>.Create(Comparison<T>) . Cette méthode peut être utilisée pour créer un IComparison à la volée.

Aussi, il jette IList<T> à IList qui a le potentiel d'être dangereux. Dans la plupart des cas que j'ai vu, List<T> qui met en œuvre IList est utilisé dans les coulisses pour mettre en œuvre IList<T> , mais ce n'est pas garanti et peut conduire à code fragile.

enfin, la méthode surchargée List<T>.Sort() a 4 signatures et seulement 2 d'entre elles sont implémentées.

  1. List<T>.Sort()
  2. List<T>.Sort(Comparison<T>)
  3. List<T>.Sort(IComparer<T>)
  4. List<T>.Sort(Int32, Int32, IComparer<T>)

la classe ci-dessous met en œuvre tous les 4 List<T>.Sort() signatures pour l'interface IList<T> :

using System;
using System.Collections.Generic;

public static class IListExtensions
{
    public static void Sort<T>(this IList<T> list)
    {
        if (list is List<T>)
        {
            ((List<T>)list).Sort();
        }
        else
        {
            List<T> copy = new List<T>(list);
            copy.Sort();
            Copy(copy, 0, list, 0, list.Count);
        }
    }

    public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
    {
        if (list is List<T>)
        {
            ((List<T>)list).Sort(comparison);
        }
        else
        {
            List<T> copy = new List<T>(list);
            copy.Sort(comparison);
            Copy(copy, 0, list, 0, list.Count);
        }
    }

    public static void Sort<T>(this IList<T> list, IComparer<T> comparer)
    {
        if (list is List<T>)
        {
            ((List<T>)list).Sort(comparer);
        }
        else
        {
            List<T> copy = new List<T>(list);
            copy.Sort(comparer);
            Copy(copy, 0, list, 0, list.Count);
        }
    }

    public static void Sort<T>(this IList<T> list, int index, int count,
        IComparer<T> comparer)
    {
        if (list is List<T>)
        {
            ((List<T>)list).Sort(index, count, comparer);
        }
        else
        {
            List<T> range = new List<T>(count);
            for (int i = 0; i < count; i++)
            {
                range.Add(list[index + i]);
            }
            range.Sort(comparer);
            Copy(range, 0, list, index, count);
        }
    }

    private static void Copy<T>(IList<T> sourceList, int sourceIndex,
        IList<T> destinationList, int destinationIndex, int count)
    {
        for (int i = 0; i < count; i++)
        {
            destinationList[destinationIndex + i] = sourceList[sourceIndex + i];
        }
    }
}

Utilisation:

class Foo
{
    public int Bar;

    public Foo(int bar) { this.Bar = bar; }
}

void TestSort()
{
    IList<int> ints = new List<int>() { 1, 4, 5, 3, 2 };
    IList<Foo> foos = new List<Foo>()
    {
        new Foo(1),
        new Foo(4),
        new Foo(5),
        new Foo(3),
        new Foo(2),
    };

    ints.Sort();
    foos.Sort((x, y) => Comparer<int>.Default.Compare(x.Bar, y.Bar));
}

l'idée ici est de tirer parti de la fonctionnalité du List<T> sous-jacent pour gérer le tri chaque fois que possible. Encore une fois, la plupart des implémentations IList<T> que j'ai vu utilisent ceci. Dans le cas où la collection sous-jacente est un type différent, retombée à la création d'une nouvelle instance de List<T> avec des éléments de la liste d'entrée, utilisez-le pour faire le tri, recopiez les résultats dans la liste des entrées. Cela fonctionnera même si la liste des entrées n'implémente pas l'interface IList .

4
répondu dana 2018-05-05 19:49:58

Convertissez votre IList en List<T> ou une autre collection générique et alors vous pouvez facilement le rechercher / le trier en utilisant System.Linq namespace (il fournira tas de méthodes d'extension)

2
répondu lubos hasko 2015-09-20 12:41:19

a trouvé ce fil pendant que je cherchais une solution au problème exact décrit dans le post original. Aucune réponse rencontré ma situation entièrement, cependant. La réponse de Brody était assez proche. Voici ma situation et la solution que j'ai trouvé.

j'ai deux Ilistes du même type retournés par NHibernate et ont émergé les deux Ilistes en un, d'où le besoin de tri.

comme Brody dit que j'ai mis en œuvre une Icom Pare sur l'objet (ReportFormat) qui est le type de mon IList:

 public class FormatCcdeSorter:IComparer<ReportFormat>
    {
       public int Compare(ReportFormat x, ReportFormat y)
        {
           return x.FormatCode.CompareTo(y.FormatCode);
        }
    }

je convertis alors L'IList fusionné à un tableau du même type:

ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList

puis trier le tableau:

Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer

puisque le tableau unidimensionnel implémente l'interface System.Collections.Generic.IList<T> , le tableau peut être utilisé tout comme L'IList original.

1
répondu John 2010-07-13 22:20:19

utile pour le tri de grille cette méthode trie la liste basée sur les noms de propriétés. Que suivre l'exemple.

    List<MeuTeste> temp = new List<MeuTeste>();

    temp.Add(new MeuTeste(2, "ramster", DateTime.Now));
    temp.Add(new MeuTeste(1, "ball", DateTime.Now));
    temp.Add(new MeuTeste(8, "gimm", DateTime.Now));
    temp.Add(new MeuTeste(3, "dies", DateTime.Now));
    temp.Add(new MeuTeste(9, "random", DateTime.Now));
    temp.Add(new MeuTeste(5, "call", DateTime.Now));
    temp.Add(new MeuTeste(6, "simple", DateTime.Now));
    temp.Add(new MeuTeste(7, "silver", DateTime.Now));
    temp.Add(new MeuTeste(4, "inn", DateTime.Now));

    SortList(ref temp, SortDirection.Ascending, "MyProperty");

    private void SortList<T>(
    ref List<T> lista
    , SortDirection sort
    , string propertyToOrder)
    {
        if (!string.IsNullOrEmpty(propertyToOrder)
        && lista != null
        && lista.Count > 0)
        {
            Type t = lista[0].GetType();

            if (sort == SortDirection.Ascending)
            {
                lista = lista.OrderBy(
                    a => t.InvokeMember(
                        propertyToOrder
                        , System.Reflection.BindingFlags.GetProperty
                        , null
                        , a
                        , null
                    )
                ).ToList();
            }
            else
            {
                lista = lista.OrderByDescending(
                    a => t.InvokeMember(
                        propertyToOrder
                        , System.Reflection.BindingFlags.GetProperty
                        , null
                        , a
                        , null
                    )
                ).ToList();
            }
        }
    }
1
répondu Bruno 2010-12-08 13:55:04

voici un exemple en utilisant le plus fort typage. Vous ne savez pas si c'est forcément de la meilleure manière.

static void Main(string[] args)
{
    IList list = new List<int>() { 1, 3, 2, 5, 4, 6, 9, 8, 7 };
    List<int> stronglyTypedList = new List<int>(Cast<int>(list));
    stronglyTypedList.Sort();
}

private static IEnumerable<T> Cast<T>(IEnumerable list)
{
    foreach (T item in list)
    {
        yield return item;
    }
}

la fonction Cast n'est qu'une réimplantation de la méthode d'extension qui vient avec 3.5 écrite comme une méthode statique normale. Il est assez laid et verbeux malheureusement.

0
répondu ICR 2008-08-19 11:38:30

dans VS2008, lorsque je clique sur la référence de service et que je sélectionne" configurer la référence de Service", il y a une option pour choisir comment le client désiscrit les listes retournées du service.

notamment, je peux choisir entre le système.Tableau, Système.Collection.Liste de tableaux et de Système.Collection.Générique.Liste

0
répondu Amy B 2008-09-17 13:33:55
using System.Linq;

var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );

c'est joli !ghetto.

0
répondu 2009-07-06 13:50:17

trouvé un bon post sur ce et pensé que je partagerais. Check it out HERE

en gros.

vous pouvez créer la classe suivante et les Classes IComparer

public class Widget {
    public string Name = string.Empty;
    public int Size = 0;

    public Widget(string name, int size) {
    this.Name = name;
    this.Size = size;
}
}

public class WidgetNameSorter : IComparer<Widget> {
    public int Compare(Widget x, Widget y) {
        return x.Name.CompareTo(y.Name);
}
}

public class WidgetSizeSorter : IComparer<Widget> {
    public int Compare(Widget x, Widget y) {
    return x.Size.CompareTo(y.Size);
}
}

alors si vous avez un IList, vous pouvez le trier comme ceci.

List<Widget> widgets = new List<Widget>();
widgets.Add(new Widget("Zeta", 6));
widgets.Add(new Widget("Beta", 3));
widgets.Add(new Widget("Alpha", 9));

widgets.Sort(new WidgetNameSorter());
widgets.Sort(new WidgetSizeSorter());

mais consultez ce site pour plus d'informations... Check it out HERE

0
répondu Mizipzor 2010-08-23 09:14:26

Est-ce une solution valable?

        IList<string> ilist = new List<string>();
        ilist.Add("B");
        ilist.Add("A");
        ilist.Add("C");

        Console.WriteLine("IList");
        foreach (string val in ilist)
            Console.WriteLine(val);
        Console.WriteLine();

        List<string> list = (List<string>)ilist;
        list.Sort();
        Console.WriteLine("List");
        foreach (string val in list)
            Console.WriteLine(val);
        Console.WriteLine();

        list = null;

        Console.WriteLine("IList again");
        foreach (string val in ilist)
            Console.WriteLine(val);
        Console.WriteLine();

le résultat a été: IList B Un C

liste Un B C

IList again Un B C

0
répondu Yoav 2010-09-11 14:10:14
try this  **USE ORDER BY** :

   public class Employee
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }

 private static IList<Employee> GetItems()
        {
            List<Employee> lst = new List<Employee>();

            lst.Add(new Employee { Id = "1", Name = "Emp1" });
            lst.Add(new Employee { Id = "2", Name = "Emp2" });
            lst.Add(new Employee { Id = "7", Name = "Emp7" });
            lst.Add(new Employee { Id = "4", Name = "Emp4" });
            lst.Add(new Employee { Id = "5", Name = "Emp5" });
            lst.Add(new Employee { Id = "6", Name = "Emp6" });
            lst.Add(new Employee { Id = "3", Name = "Emp3" });

            return lst;
        }

**var lst = GetItems().AsEnumerable();

            var orderedLst = lst.OrderBy(t => t.Id).ToList();

            orderedLst.ForEach(emp => Console.WriteLine("Id - {0} Name -{1}", emp.Id, emp.Name));**
0
répondu Dhanasekar 2012-08-31 08:02:56