Question

Je suis donc tombé sur un problème intéressant aujourd'hui.Nous avons un service Web WCF qui renvoie une IList.Ce n’était pas vraiment grave jusqu’à ce que je veuille régler le problème.

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

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

J'ai joué avec l'écriture d'une méthode d'extension, également avec l'héritage de IList et l'implémentation de ma propre méthode Sort() ainsi que la conversion en une liste, mais aucune d'entre elles ne semblait trop élégante.

Ma question est donc la suivante : est-ce que quelqu'un a une solution élégante pour trier une liste IList ?

Était-ce utile?

La solution

Que diriez-vous d'utiliser LINQ To Objects pour trier à votre place ?

Dis que tu as un IList<Car>, et la voiture avait un Engine propriété, je pense que vous pourriez trier comme suit :

from c in list
orderby c.Engine
select c;

Modifier:Vous devez ê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 laisserai ma réponse - cependant, les autres réponses présentées sont également valables.

Autres conseils

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

Cette question m'a inspiré pour écrire un article 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<T>, mais la meilleure chose à faire 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<T> comme vous le feriez pour un List<T>.En prime, vous pouvez surcharger la méthode d'extension LINQ OrderBy en utilisant la même technique, de sorte que, que vous utilisiez List.Sort, IList.Sort ou IEnumerable.OrderBy, vous puissiez utiliser exactement 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 IList comme vous le feriez pour 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'informations dans le post : http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

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

Peut-être le placer dans une liste de T plutôt que dans une ArrayList, afin d'obtenir la sécurité du type et plus d'options sur la façon dont vous implémentez le comparateur.

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 le ComparisonComparer<T> classe lorsque le framework inclut 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.

En outre, il lance IList<T> à IList ce qui peut être potentiellement dangereux.Dans la plupart des cas que j'ai vus, List<T> qui met en œuvre IList est utilisé en coulisses pour mettre en œuvre IList<T>, mais cela n'est pas garanti et peut conduire à un code fragile.

Enfin, la surcharge List<T>.Sort() La méthode 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 implémente les 4 List<T>.Sort() signatures pour le IList<T> interface:

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

Usage:

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 d'exploiter les fonctionnalités du sous-jacent List<T> gérer le tri dans la mesure du possible.Encore une fois, la plupart IList<T> les implémentations que j'ai vues l'utiliser.Dans le cas où la collection sous-jacente est d'un type différent, créez une nouvelle instance de List<T> avec des éléments de la liste d'entrée, utilisez-le pour effectuer le tri, puis recopiez les résultats dans la liste d'entrée.Cela fonctionnera même si la liste d'entrée n'implémente pas le IList interface.

J'ai trouvé ce fil alors que je cherchais une solution au problème exact décrit dans le message d'origine.Cependant, aucune des réponses ne correspondait entièrement à ma situation.La réponse de Brody était assez proche.Voici ma situation et la solution que j'y ai trouvée.

J'ai deux IListes du même type renvoyées par NHibernate et j'ai fusionné les deux IListes en une seule, d'où la nécessité d'un tri.

Comme Brody l'a dit, j'ai implémenté un ICompare 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 ensuite l'IList fusionné en un tableau du même type :

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

Triez ensuite 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é comme l'IList d'origine.

Utile pour le tri sur grille, cette méthode trie la liste en fonction des noms de propriétés.Comme suivez 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();
            }
        }
    }
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));**

Convertissez votre IList dans List<T> ou une autre collection générique et vous pouvez ensuite l'interroger/trier facilement en utilisant System.Linq espace de noms (il fournira un tas de méthodes d'extension)

Voici un exemple utilisant la frappe plus forte.Je ne sais pas si c'est nécessairement la meilleure façon.

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éimplémentation de la méthode d'extension fournie avec la version 3.5 écrite comme une méthode statique normale.C'est malheureusement assez moche et verbeux.

Dans VS2008, lorsque je clique sur la référence du service et que je sélectionne « Configurer la référence du service », il existe une option permettant de choisir comment le client désérialise les listes renvoyées par le service.

Notamment, je peux choisir entre System.Array, System.Collections.ArrayList et System.Collections.Generic.List

using System.Linq;

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

C'est joli !ghetto.

J'ai trouvé un bon article à ce sujet et j'ai pensé le partager. Vérifiez le ici

Essentiellement.

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

Ensuite, si vous avez une IList, vous pouvez la 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... Vérifiez le ici

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 fut :Ilist b a c

Liste A B C

Ilist encore un b c

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top