myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Datentechnologien » Extension mit LINQ: Auf angegebene Eigenschaft zugreifen ... MyList.AddSorted(item, x => x.Property)
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

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

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Beauty
myCSharp.de-Mitglied

avatar-2333.jpg


Dabei seit: 31.05.2007
Beiträge: 79
Entwicklungsumgebung: Visual C# 2008
Herkunft: Thüringen


Beauty ist offline

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

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

verwendete Technologie: LINQ

Aufruf:

C#-Code:
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).

C#-Code:
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 11.12.2015 18:10.

11.12.2015 18:08 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.177
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

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
11.12.2015 18:26 Beiträge des Benutzers | zu Buddylist hinzufügen
LaTino LaTino ist männlich
myCSharp.de-Poweruser/ Experte

avatar-4122.png


Dabei seit: 03.04.2006
Beiträge: 2.969
Entwicklungsumgebung: Rider / VS2019 / VS Code
Herkunft: Thüringen


LaTino ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

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:

C#-Code:
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 Augenzwinkern

Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von LaTino am 12.12.2015 09:13.

12.12.2015 09:10 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Beauty
myCSharp.de-Mitglied

avatar-2333.jpg


Dabei seit: 31.05.2007
Beiträge: 79
Entwicklungsumgebung: Visual C# 2008
Herkunft: Thüringen

Themenstarter Thema begonnen von Beauty

Beauty ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

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:

C#-Code:
/// <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);
}
29.12.2015 09:44 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Lando Lando ist männlich
myCSharp.de-Mitglied

avatar-3452.jpg


Dabei seit: 14.05.2014
Beiträge: 73
Entwicklungsumgebung: VS 2013


Lando ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

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
29.12.2015 20:13 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 12.926
Herkunft: Stuttgart/Stockholm


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Die Schreibweise nennt man aber Lambda.
29.12.2015 20:37 Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.177
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

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
29.12.2015 23:25 Beiträge des Benutzers | zu Buddylist hinzufügen
ErfinderDesRades
myCSharp.de-Poweruser/ Experte

avatar-3151.jpg


Dabei seit: 31.01.2008
Beiträge: 5.286


ErfinderDesRades ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

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 04.01.2016 10:58.

04.01.2016 10:56 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 3 Jahre.
Der letzte Beitrag ist älter als 3 Jahre.
Antwort erstellen


© Copyright 2003-2019 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 24.08.2019 18:19