Pregunta

Así que hoy me encontré con un problema interesante.Tenemos un servicio web WCF que devuelve una IList.Realmente no fue gran cosa hasta que quise solucionarlo.

Resulta que la interfaz IList no tiene un método de clasificación integrado.

Terminé usando el ArrayList.Adapter(list).Sort(new MyComparer()) método para resolver el problema, pero me pareció un poco "gueto".

Jugué con escribir un método de extensión, también con heredar de IList e implementar mi propio método Sort(), así como convertirlo en una Lista, pero ninguno de estos parecía demasiado elegante.

Entonces mi pregunta es, ¿alguien tiene una solución elegante para ordenar una IList?

¿Fue útil?

Solución

¿Qué tal si utilizamos LINQ To Objects para ordenar por usted?

Di que tienes un IList<Car>, y el auto tenía un Engine propiedad, creo que se podría ordenar de la siguiente manera:

from c in list
orderby c.Engine
select c;

Editar:Debe ser rápido para obtener respuestas aquí.Como presenté una sintaxis ligeramente diferente a las otras respuestas, dejaré mi respuesta; sin embargo, las otras respuestas presentadas son igualmente válidas.

Otros consejos

Puedes usar LINQ:

using System.Linq;

IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();

Esta pregunta me inspiró a escribir una publicación de blog: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

Creo que, idealmente, .NET Framework incluiría un método de clasificación estático que acepte un IList<T>, pero la mejor opción es crear su propio método de extensión.No es demasiado difícil crear un par de métodos que le permitan ordenar una IList<T> como lo haría con una List<T>.Como beneficio adicional, puede sobrecargar el método de extensión LINQ OrderBy usando la misma técnica, de modo que ya sea que esté usando List.Sort, IList.Sort o IEnumerable.OrderBy, pueda usar exactamente la misma sintaxis.

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

Con estas extensiones, ordene su IList como lo haría con una Lista:

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

Hay más información en la publicación: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

Creo que tendrás que hacer algo así (convertirlo en un tipo más concreto).

Tal vez llévelo a una Lista de T en lugar de ArrayList, para obtener seguridad de tipos y más opciones sobre cómo implementar el comparador.

La respuesta aceptada por @DavidMills es bastante buena, pero creo que se puede mejorar.Por un lado, no es necesario definir el ComparisonComparer<T> clase cuando el marco ya incluye un método estático Comparer<T>.Create(Comparison<T>).Este método se puede utilizar para crear un IComparison sobre la marcha.

Además, arroja IList<T> a IList que tiene el potencial de ser peligroso.En la mayoría de los casos que he visto, List<T> que implementa IList se utiliza detrás de escena para implementar IList<T>, pero esto no está garantizado y puede provocar un código frágil.

Por último, el sobrecargado List<T>.Sort() El método tiene 4 firmas y solo 2 de ellas están implementadas.

  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 siguiente clase implementa los 4 List<T>.Sort() firmas para el IList<T> interfaz:

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

Uso:

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

La idea aquí es aprovechar la funcionalidad del subyacente List<T> encargarse de la clasificación siempre que sea posible.De nuevo, la mayoría IList<T> implementaciones que he visto usan esto.En el caso de que la colección subyacente sea de un tipo diferente, recurra a la creación de una nueva instancia de List<T> con elementos de la lista de entrada, úselo para ordenar y luego copie los resultados nuevamente a la lista de entrada.Esto funcionará incluso si la lista de entrada no implementa la IList interfaz.

Encontré este hilo mientras buscaba una solución al problema exacto descrito en la publicación original.Sin embargo, ninguna de las respuestas se ajustaba completamente a mi situación.La respuesta de Brody fue bastante cercana.Aquí está mi situación y la solución que encontré.

Tengo dos ILList del mismo tipo devueltos por NHibernate y he convertido los dos IList en uno, de ahí la necesidad de ordenar.

Como dijo Brody, implementé un ICompare en el objeto (ReportFormat) que es el tipo de mi IList:

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

Luego convierto la IList fusionada en una matriz del mismo tipo:

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

Luego ordena la matriz:

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

Dado que la matriz unidimensional implementa la interfaz System.Collections.Generic.IList<T>, la matriz se puede utilizar igual que la IList original.

Útil para ordenar cuadrículas, este método ordena la lista según los nombres de propiedades.Como sigue el ejemplo.

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

Convierte tu IList en List<T> o alguna otra colección genérica y luego puedes consultarla/ordenarla fácilmente usando System.Linq espacio de nombres (proporcionará un montón de métodos de extensión)

A continuación se muestra un ejemplo que utiliza la escritura más fuerte.Sin embargo, no estoy seguro de si es necesariamente la mejor manera.

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 función Cast es solo una reimplementación del método de extensión que viene con 3.5 escrito como un método estático normal.Desafortunadamente, es bastante feo y detallado.

En VS2008, cuando hago clic en la referencia del servicio y selecciono "Configurar referencia del servicio", hay una opción para elegir cómo el cliente deserializa las listas devueltas por el servicio.

En particular, puedo elegir entre System.Array, System.Collections.ArrayList y System.Collections.Generic.List

using System.Linq;

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

¡Eso es bonito! gueto.

Encontré una buena publicación sobre esto y pensé en compartirla. Compruébalo AQUÍ

Básicamente.

Puede crear la siguiente clase y clases 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);
}
}

Luego, si tiene una IList, puede ordenarla así.

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

Pero visita este sitio para obtener más información... Compruébalo AQUÍ

¿Es esta una solución válida?

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

El resultado fue:Ilist b a c

Lista A B C

Ilist nuevamente A B C

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top