Frage

Daher bin ich heute auf ein interessantes Problem gestoßen.Wir haben einen WCF-Webdienst, der eine IList zurückgibt.Eigentlich keine große Sache, bis ich es klären wollte.

Es stellt sich heraus, dass in der IList-Schnittstelle keine Sortiermethode integriert ist.

Am Ende habe ich das verwendet ArrayList.Adapter(list).Sort(new MyComparer()) Methode, um das Problem zu lösen, aber es schien mir einfach ein bisschen „Ghetto“ zu sein.

Ich habe mit dem Schreiben einer Erweiterungsmethode gespielt, auch damit, von IList zu erben und meine eigene Sort()-Methode zu implementieren sowie in eine Liste umzuwandeln, aber nichts davon erschien mir übermäßig elegant.

Meine Frage ist also: Hat jemand eine elegante Lösung zum Sortieren einer IList?

War es hilfreich?

Lösung

Wie wäre es, wenn Sie LINQ To Objects zum Sortieren verwenden würden?

Angenommen, Sie haben ein IList<Car>, und das Auto hatte eine Engine Eigentum, ich glaube, Sie könnten wie folgt sortieren:

from c in list
orderby c.Engine
select c;

Bearbeiten:Hier muss man schnell sein, um Antworten zu bekommen.Da ich eine etwas andere Syntax als die anderen Antworten angegeben habe, belasse ich meine Antwort – die anderen Antworten sind jedoch gleichermaßen gültig.

Andere Tipps

Sie können LINQ verwenden:

using System.Linq;

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

Diese Frage hat mich dazu inspiriert, einen Blogbeitrag zu schreiben: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

Ich denke, dass das .NET Framework im Idealfall eine statische Sortiermethode enthalten würde, die ein IList<T> akzeptiert, aber das nächstbeste wäre, eine eigene Erweiterungsmethode zu erstellen.Es ist nicht allzu schwierig, ein paar Methoden zu erstellen, mit denen Sie eine IList<T> wie eine List<T> sortieren können.Als Bonus können Sie die LINQ-OrderBy-Erweiterungsmethode mit derselben Technik überladen, sodass Sie unabhängig davon, ob Sie List.Sort, IList.Sort oder IEnumerable.OrderBy verwenden, genau dieselbe Syntax verwenden können.

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

Mit diesen Erweiterungen können Sie Ihre IList wie eine Liste sortieren:

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

Weitere Infos gibt es im Beitrag: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

Ich denke, Sie müssen so etwas tun (es in einen konkreteren Typ umwandeln).

Nehmen Sie es vielleicht in eine Liste von T statt in eine ArrayList auf, damit Sie Typsicherheit und mehr Optionen für die Implementierung des Vergleichers erhalten.

Die akzeptierte Antwort von @DavidMills ist ziemlich gut, aber ich denke, sie kann verbessert werden.Zum einen besteht keine Notwendigkeit, das zu definieren ComparisonComparer<T> Klasse, wenn das Framework bereits eine statische Methode enthält Comparer<T>.Create(Comparison<T>).Mit dieser Methode kann eine erstellt werden IComparison im laufenden Betrieb.

Außerdem wirft es IList<T> Zu IList was das Potenzial hat, gefährlich zu sein.In den meisten Fällen, die ich gesehen habe, List<T> was umsetzt IList wird hinter den Kulissen zur Umsetzung genutzt IList<T>, Dies ist jedoch nicht garantiert und kann zu brüchigem Code führen.

Zuletzt die Überlastung List<T>.Sort() Die Methode hat 4 Signaturen und nur 2 davon sind implementiert.

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

Die folgende Klasse implementiert alle 4 List<T>.Sort() Unterschriften für die IList<T> Schnittstelle:

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

Verwendung:

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

Die Idee hierbei ist, die Funktionalität des Basiswerts zu nutzen List<T> um die Sortierung zu übernehmen, wann immer es möglich ist.Wieder die meisten IList<T> Implementierungen, die ich gesehen habe, verwenden dies.Wenn es sich bei der zugrunde liegenden Sammlung um einen anderen Typ handelt, können Sie auf die Erstellung einer neuen Instanz von zurückgreifen List<T> mit Elementen aus der Eingabeliste, verwenden Sie es zum Sortieren und kopieren Sie dann die Ergebnisse zurück in die Eingabeliste.Dies funktioniert auch dann, wenn die Eingabeliste das nicht implementiert IList Schnittstelle.

Ich habe diesen Thread gefunden, als ich nach einer Lösung für genau das im ursprünglichen Beitrag beschriebene Problem suchte.Keine der Antworten traf jedoch meine Situation vollständig.Brodys Antwort kam ziemlich nahe.Hier ist meine Situation und die Lösung, die ich dafür gefunden habe.

Ich habe zwei ILists des gleichen Typs von NHibernate zurückgegeben und die beiden ILists zu einer zusammengefasst, daher ist eine Sortierung erforderlich.

Wie Brody sagte, habe ich einen ICompare für das Objekt (ReportFormat) implementiert, das dem Typ meiner IList entspricht:

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

Anschließend konvertiere ich die zusammengeführte IList in ein Array desselben Typs:

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

Dann sortieren Sie das Array:

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

Da ein eindimensionales Array die Schnittstelle implementiert System.Collections.Generic.IList<T>, kann das Array genau wie die ursprüngliche IList verwendet werden.

Diese Methode ist nützlich für die Rastersortierung und sortiert die Liste nach Eigenschaftsnamen.Folgen Sie dem Beispiel.

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

Konvertieren Sie Ihre IList hinein List<T> oder eine andere generische Sammlung, mit der Sie sie dann einfach abfragen/sortieren können System.Linq Namespace (er stellt eine Reihe von Erweiterungsmethoden bereit)

Hier ist ein Beispiel mit der stärkeren Typisierung.Ich bin mir jedoch nicht sicher, ob es unbedingt der beste Weg ist.

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

Die Cast-Funktion ist lediglich eine Neuimplementierung der Erweiterungsmethode, die mit 3.5 geliefert wird und als normale statische Methode geschrieben ist.Es ist leider ziemlich hässlich und ausführlich.

Wenn ich in VS2008 auf die Dienstreferenz klicke und „Dienstreferenz konfigurieren“ auswähle, gibt es eine Option zum Auswählen, wie der Client die vom Dienst zurückgegebenen Listen deserialisiert.

Insbesondere kann ich zwischen System.Array, System.Collections.ArrayList und System.Collections.Generic.List wählen

using System.Linq;

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

Das ist ein hübsches Ghetto.

Ich habe einen guten Beitrag dazu gefunden und dachte, ich würde ihn teilen. Schauen Sie es sich HIER an

Grundsätzlich.

Sie können die folgenden Klassen und IComparer-Klassen erstellen

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

Wenn Sie dann eine IList haben, können Sie diese wie folgt sortieren.

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

Aber schauen Sie sich diese Seite an, um weitere Informationen zu erhalten ... Schauen Sie es sich HIER an

Ist das eine gültige Lösung?

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

Das Ergebnis war:Ilist b a c

Liste A B C

IList wieder A B C

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top