Laden...

Extension mit LINQ: Auf angegebene Eigenschaft zugreifen ... MyList.AddSorted(item, x => x.Property)

Erstellt von Beauty vor 8 Jahren Letzter Beitrag vor 8 Jahren 3.442 Views
Beauty Themenstarter:in
79 Beiträge seit 2007
vor 8 Jahren
Extension mit LINQ: Auf angegebene Eigenschaft zugreifen ... MyList.AddSorted(item, x => x.Property)

verwendete Technologie: LINQ

Aufruf:


MyList.AddSorted(newItem, x => x.PROPERTY);

Ziel:
In die Liste MyList soll das Element newItem eingefügt werden.
Und zwar an die "richtige" Stelle. (alphabetisch bei String, numerisch bei Zahl, etc.)
Der Lambda-Ausdruck gibt an, welche Eigenschaft (PROPERTY) des Objekts mit CompareTo() verglichen werden soll.

Annahme:
Es handelt sich um eine vorsortierte Liste.

Beispiel:
In Liste { 1, 3, 5 } wird 4 hinzugefügt, dann wird sie zu { 1, 3, 4, 5 }.
(Bezogen auf die Werte in der angegebenen Eigenschaft.)

Lösungsansatz:
Eine Erweiterung des Listen-Klassentyps (z. B. ObservableCollection).


public static void AddSorted<TSource, TKey>(this IList<TSource> list, TSource item, Func<TSource, TKey> keySelector)
{
    Int32 insertPosition = list.Count; // by default add to the end
    if (item.PROPERTY is IComparable<TSource>)
    {
        for (Int32 i = 0;   i < list.Count;   i++)
        {
            if (list[i].PROPERTY.CompareTo(item.PROPERTY) > 0)
            {
                insertPosition = i;
                break;
            }
        }
    }
    list.Insert(insertPosition, item);
}

Mein Problem:
Wie schreibt man den Code, daß auf die im Lambda-Ausdruck angegebene Eigenschaft zugegriffen wird?
Der String PROPERTY im Code ist ein Platzhalter.

Ich habe schon eine Weile im Netz und im Forum gesucht. Und auch Herumprobiert. Leider fand ich keine Lösung.

Über eine hilfreiche Antwort würde ich mich freuen.

P.S.
SortedList<> ist für mich keine Option, da ich es für eine ObservableCollection brauche.
Außerdem möchte ich in Sachen Technologie dazulernen.

5.657 Beiträge seit 2006
vor 8 Jahren

Hi Beauty,

mit Linq hat das nicht viel zu tun. Linq ist, wie der Name ja andeutet, zum Abfragen von Daten gemacht, und nicht zum Verändern von Listen.

Was du hast, ist eine Erweiterungsmethode für IList. Was du brauchst, ist eine sortierte ObservableCollection. Hier gibt es eine Lösung für beides: Keeping an ObservableCollection sorted with a method override.

Dein konkretes Problem wird wohl dadurch verursacht, daß du stattdessen die keySelector-Delegaten mit den entsprechenden Parametern aufrufen wolltest.

Christian

Weeks of programming can save you hours of planning

3.003 Beiträge seit 2006
vor 8 Jahren

Ergänzend - wenn du eine Methode schreiben willst, die einen Delegaten als Argument hat (p => p.Property ist ein delegat), dann schau dir A(ction) und Func(tion) an. Damit sollte sich dein Problem auf die Weise lösen lassen, die du im Sinn hast.

Stub:


static void AddSorted(this IEnumerable<MyClass> liste, MyClass addObject, Func<IComparable,MyClass> f)
{
        //...schleife..
        if(f(addObject).CompareTo(f(liste[i]))) > 0)
        {
             liste.InsertAt(i,addObject);
             break;
         }
}
//Aufruf
myList.AddSorted(newObject, p => p.PropertyName);
//todo: sicherstellen, dass die Properties, die Verglichen werden, auch IComparable sind

LaTino
EDIT: ich hätte vermutlich einfach hinzugefügt und dann neu sortiert; momentan verhindern Kopfschmerzen aber, dass ich erfolgreich darüber nachdenken kann, was effizienter ist 😉

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

Beauty Themenstarter:in
79 Beiträge seit 2007
vor 8 Jahren

Hallo MrSparcle und LaTino,

danke für Eure hilfreichen Antworten.

mit Linq hat das nicht viel zu tun.

Ich dachte das sei LINQ, weil ich die Schreibweise x => x.yy bisher nur von LINQ kenne.
Jemand mit Admin-Rechten könnte das Thema verschieben.

Was du brauchst, ist eine sortierte ObservableCollection.

In meinem Fall wollte ich keine Liste neu sortierten, sondern ein Element in eine bereits vorsortierte Liste eintragen.
Außerdem wollte ich in Sachen Technologie dazulernen.

Hier meine Lösung, die ich schon an mehreren Stellen verwenden konnte:


/// <summary>
/// Add an item to the related position of an already sorted list.
/// By the keySelector parameter you can define which property of the item should be used for comparison.
/// </summary>
/// <typeparam name="TSource">Type of the item, which to insert</typeparam>
/// <typeparam name="TKey">Property of the item, which is used for comparison</typeparam>
/// <param name="list">List where to add the item</param>
/// <param name="item">Item, which to add</param>
/// <param name="keySelector">Definition of the property which to choose for comparison</param>
public static void AddSorted<TSource, TKey>(this IList<TSource> list, TSource item, Func<TSource, TKey> keySelector)
{
    Int32 insertPosition = list.Count; // by default add to the end
    if (keySelector(item) is IComparable<TKey>)
    {
        for (Int32 i = 0;   i < list.Count;   i++)
        {
            if (((IComparable<TKey>)keySelector(item)).CompareTo(keySelector(list[i])) < 0)
            {
                insertPosition = i;
                break;
            }
        }
    }
    list.Insert(insertPosition, item);
}

74 Beiträge seit 2014
vor 8 Jahren

Du solltest noch den TKey-Typ mit where TKey : IComparable<TKey> einschränken, damit der Compiler seinen Job tun kann und du nicht casten brauchst.

Grüße

16.807 Beiträge seit 2008
vor 8 Jahren

Die Schreibweise nennt man aber Lambda.

5.657 Beiträge seit 2006
vor 8 Jahren

Da es sich bei der Liste um bereits sortierte Daten handelt, kann man auch eine binäre Suche verwenden, um die Einfügeposition zu ermitteln. Ganz allgemein gibt es aber bessere Datenstrukturen, um sortierte Auflistungen bereitzuhalten, als eine einfache Liste.

Christian

Weeks of programming can save you hours of planning

5.299 Beiträge seit 2008
vor 8 Jahren

zustimm.
List<T> und Array stellen übrigens finxnfertige BinarySearch-Funktionalität bereit, auch Überladungen mit benutzerdefinierten Sortierkriterien.

Ob das optimal ist, ist andere Frage, BinarySearch ist zumindest sehr sehr schnell - afaik kaum noch zu toppen.
Das langsamste dabei ist das Inserten, aber auch das ist bei Array und List<T> hochoptimiert, also "langsam" ist da sehr relativ.

Der frühe Apfel fängt den Wurm.