Domanda

Così mi sono imbattuto in un interessante problema di oggi.Abbiamo un WCF web service che restituisce un IList.Non è davvero un grosso problema fino a quando ho voluto ordinare.

Si rivelasse l'interfaccia IList non dispone di un metodo di ordinamento integrato.

Ho finito per usare il ArrayList.Adapter(list).Sort(new MyComparer()) metodo per risolvere il problema, ma mi sembrava un po ' "ghetto" per me.

Ho giocato con la scrittura di un metodo di estensione, anche con ereditando da IList e l'implementazione del proprio metodo Sort (), come pure il casting per un Elenco, ma nessuno di questi sembrava troppo elegante.

Quindi la mia domanda è, qualcuno ha una soluzione elegante per l'ordinamento di una IList

È stato utile?

Soluzione

Come sull'utilizzo di LINQ To Objects per ordinare per voi?

Dici di avere una IList<Car>, e la macchina aveva un Engine la struttura, credo che si potrebbe risolvere come segue:

from c in list
orderby c.Engine
select c;

Edit:Hai bisogno di essere veloce per ottenere risposte qui.Come ho presentato una sintassi leggermente diversa per le altre risposte, vorrei lasciare la mia risposta - tuttavia, le altre risposte presentati sono ugualmente valide.

Altri suggerimenti

È possibile utilizzare LINQ:

using System.Linq;

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

Questa domanda mi ha ispirato a scrivere un post del blog: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

Penso che, idealmente, l' .NET Framework include una statico metodo di ordinamento che accetta un IList<T>ma la cosa migliore è quello di creare il proprio metodo di estensione.Non è troppo difficile creare un paio di metodi che consentono di ordinare un IList<T> come un Elenco<T>.Come bonus è possibile sovraccarico LINQ OrderBy metodo di estensione utilizzando la stessa tecnica, in modo che se si sta utilizzando l'Elenco.Sorta, IList.Ordinamento, o IEnumerable.OrderBy, si può usare la stessa sintassi.

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 queste estensioni, ordina i tuoi IList proprio come in un Elenco:

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

C'è di più info nel post: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

Si sta andando ad avere per fare qualcosa di simile che credo (conversione in un più concreto tipo).

Forse portarlo in un Elenco di T, piuttosto che ArrayList, in modo che si ottiene il tipo di sicurezza e più opzioni per implementare l'operatore di confronto.

Accettato risposta da @DavidMills è abbastanza buona, ma penso che può essere migliorato.Per uno, non c'è bisogno di definire il ComparisonComparer<T> classe quando il framework include già un metodo statico Comparer<T>.Create(Comparison<T>).Questo metodo può essere utilizzato per creare un IComparison al volo.

Inoltre, si getta IList<T> per IList che ha il potenziale per essere pericoloso.Nella maggior parte dei casi che ho visto, List<T> che implementa IList è utilizzato dietro le quinte per implementare IList<T>, ma questo non è garantito e può portare a fragili codice.

Infine, l'overload List<T>.Sort() metodo 4 di firme e solo 2 di loro sono implementate.

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

Al di sotto di classe implementa tutte e 4 List<T>.Sort() le firme per il IList<T> interfaccia:

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

Utilizzo:

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'idea è quella di sfruttare la funzionalità del sottostante List<T> per gestire l'ordinamento, quando possibile.Ancora una volta, più IList<T> implementazioni che ho visto utilizzare questo.Nel caso In cui il sottostante collezione è un diverso tipo di fallback per la creazione di una nuova istanza di List<T> con elementi della lista di ingresso, si usa per eseguire l'ordinamento, quindi copiare i risultati per la lista di ingresso.Questo funziona anche se la lista di ingresso non implementare il IList l'interfaccia.

Trovato questo thread mentre ero alla ricerca di una soluzione per il problema descritto nel post originale.Nessuna delle risposte incontrato la mia situazione del tutto, però.Brody risposta è stata abbastanza vicino.Ecco la mia situazione e la soluzione che ho trovato per farlo.

Ho due ILists dello stesso tipo restituito da NHibernate e sono emerse due IList in uno, da qui la necessità per l'ordinamento.

Come disse Brody ho implementato un ICompare sull'oggetto (ReportFormat) che è il tipo di mia IList:

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

Ho quindi la conversione unita IList a una matrice dello stesso tipo:

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

Quindi ordinare l'array:

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

Poiché la matrice unidimensionale implementa l'interfaccia System.Collections.Generic.IList<T>, l'array può essere utilizzato proprio come l'originale IList.

Utile per la griglia di ordinamento di questo metodo sorta di elenco di nomi di proprietà.Come seguire l'esempio.

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

Convertire il vostro IList in List<T> o qualche altra raccolta generica e quindi si può facilmente query/sort utilizzando System.Linq spazio dei nomi (che fornirà sacco di metodi di estensione)

Ecco un esempio di utilizzo il più forte di battitura.Non so se è necessariamente il modo migliore però.

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 funzione Cast è solo una reimplementazione del metodo di estensione che viene fornito con 3.5 scritto come un normale metodo statico.È abbastanza brutto e dettagliato, purtroppo.

Nel 2008, quando faccio clic su di riferimento del servizio e selezionare "Configura Riferimento al Servizio", c'è un'opzione per scegliere il modo in cui il client deserializza liste restituito dal servizio.

In particolare, posso scegliere tra il Sistema.Matrice Del Sistema.Collezioni.ArrayList e di Sistema.Collezioni.Generico.Elenco

using System.Linq;

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

Che bella !ghetto.

Trovato un post su questo e ho pensato di condividere. Check it out QUI

Fondamentalmente.

È possibile creare la seguente classe e IComparer Classi

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

Quindi, Se si dispone di un IList, è possibile ordinare questo.

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

Ma Checkout questo sito per ulteriori informazioni... Check it out QUI

Questa è una soluzione valida?

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

Il risultato è stato:IList B Un C

Elenco Un B C

IList di nuovo Un B C

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top