Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

Extension mit LINQ: Auf angegebene Eigenschaft zugreifen ... MyList.AddSorted(item, x => x.Property)
Beauty
myCSharp.de - Member

Avatar #avatar-2333.jpg


Dabei seit:
Beiträge: 83
Herkunft: Thüringen

Themenstarter:

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

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Beauty am .
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5992
Herkunft: Leipzig

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3062
Herkunft: Thüringen

beantworten | zitieren | melden

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
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von LaTino am .
"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)
private Nachricht | Beiträge des Benutzers
Beauty
myCSharp.de - Member

Avatar #avatar-2333.jpg


Dabei seit:
Beiträge: 83
Herkunft: Thüringen

Themenstarter:

beantworten | zitieren | melden

Hallo MrSparcle und LaTino,

danke für Eure hilfreichen Antworten.
Zitat
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.
Zitat
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);
}
private Nachricht | Beiträge des Benutzers
Lando
myCSharp.de - Member

Avatar #avatar-3452.jpg


Dabei seit:
Beiträge: 74

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 16214

beantworten | zitieren | melden

Die Schreibweise nennt man aber Lambda.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5992
Herkunft: Leipzig

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5409

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ErfinderDesRades am .
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers