Sortieren Sie eine Liste nach einer anderen

73

Ich habe 2 Listenobjekte, eines ist nur eine Liste von Ints, das andere ist eine Liste von Objekten, aber die Objekte haben eine ID-Eigenschaft.

Was ich tun möchte, ist die Liste der Objekte nach ihrer ID in der gleichen Sortierreihenfolge wie die Liste der Ints zu sortieren.

Ich habe eine Weile herumgespielt und versucht, es zum Laufen zu bringen, bisher keine Freude,

Hier ist was ich bisher habe ...

//**************************
//*** Randomize the list ***
//**************************
if (Session["SearchResultsOrder"] != null)
{
    // save the session as a int list
    List<int> IDList = new List<int>((List<int>)Session["SearchResultsOrder"]);
    // the saved list session exists, make sure the list is orded by this
    foreach(var i in IDList)
    {
        SearchData.ReturnedSearchedMembers.OrderBy(x => x.ID == i);
    }
}
else
{
    // before any sorts randomize the results - this mixes it up a bit as before it would order the results by member registration date                        
    List<Member> RandomList = new List<Member>(SearchData.ReturnedSearchedMembers);
    SearchData.ReturnedSearchedMembers = GloballyAvailableMethods.RandomizeGenericList<Member>(RandomList, RandomList.Count).ToList();

    // save the order of these results so they can be restored back during postback
    List<int> SearchResultsOrder = new List<int>();
    SearchData.ReturnedSearchedMembers.ForEach(x => SearchResultsOrder.Add(x.ID));
    Session["SearchResultsOrder"] = SearchResultsOrder;
}   

Der springende Punkt dabei ist, dass ein Benutzer, wenn er nach Mitgliedern sucht, diese zunächst in zufälliger Reihenfolge anzeigt. Wenn er dann auf Seite 2 klickt, bleiben sie in dieser Reihenfolge und die nächsten 20 Ergebnisse werden angezeigt.

Ich habe über den ICompare gelesen, den ich als Parameter in der Linq.OrderBy-Klausel verwenden kann, aber ich kann keine einfachen Beispiele finden.

Ich hoffe auf eine elegante, sehr einfache Lösung im LINQ-Stil, und ich kann immer hoffen.

Jede Hilfe wird am meisten geschätzt.

JGilmartin
quelle
5
Haben Sie darüber nachgedacht, einen Linq-Join zwischen den beiden Listen durchzuführen und dann eine Sortierung durchzuführen?
RQDQ
Hinweis: Sie müssen die ursprüngliche Bestellung als Wörterbuch speichern: ID 2-Index.
Hamish Grubijan
3
Mögliches Duplikat von stackoverflow.com/questions/3470098/…
goodeye

Antworten:

119

Ein weiterer LINQ-Ansatz:

 var orderedByIDList = from i in ids 
                       join o in objectsWithIDs
                       on i equals o.ID
                       select o;
Simon D.
quelle
7
Meine persönliche Erfahrung ist, dass Linq im Allgemeinen eine viel bessere Leistung erbringt als viele Leute denken. In den meisten Fällen handelt es sich nur um syntaktischen Zucker, der am Ende dieselben Operationen wie anderer Code ausführt, sodass Sie den Unterschied normalerweise nicht spüren. Eigentlich weiß ich für diesen speziellen Fall nur, dass es funktioniert. Wenn es nicht gut funktioniert, müssen Sie eine völlig andere Datenstruktur wählen, da dieser vollständige Listen-Join immer einige Zeit in Anspruch nimmt, egal wie Sie es tun.
Simon D.
25

Eine Möglichkeit, dies zu tun:

List<int>  order = ....;
List<Item> items = ....;

Dictionary<int,Item> d = items.ToDictionary(x => x.ID);

List<Item> ordered = order.Select(i => d[i]).ToList();
Jimmy
quelle
1
Sie gehen davon aus, dass für jedes int in der Bestellliste ein entsprechender Artikel in der Artikelliste vorhanden ist ...
Justin Lang
1
order.Where(d.ContainsKey).Select(...)oder Select / SelectMany mit einer längeren Funktion, die TryGetValue verwendet, löst dieses Problem.
Jimmy
15

Keine Antwort auf diese genaue Frage, aber wenn Sie zwei Arrays haben , gibt es eine Überladung Array.Sort, bei der das Array sortiert und ein Array als 'Schlüssel' verwendet werden muss.

https://msdn.microsoft.com/en-us/library/85y6y2d3.aspx

Array.Sort-Methode (Array, Array)
Sortiert ein Paar eindimensionaler Array-Objekte (eines enthält die Schlüssel und das andere enthält die entsprechenden Elemente) basierend auf den Schlüsseln im ersten Array unter Verwendung der IComparable-Implementierung jedes Schlüssels.

Mark Sowul
quelle
1
Irgendeine Idee, wie dies für Listen funktioniert? Ich bin hier, weil ich mit Listen arbeiten muss und diese schöne Array-Sortierung nicht verwenden kann.
Bitterblue
9

Joinist der beste Kandidat, wenn Sie mit der exakten Ganzzahl übereinstimmen möchten (wenn keine Übereinstimmung gefunden wird, erhalten Sie eine leere Sequenz). Wenn Sie lediglich die Sortierreihenfolge der anderen Liste abrufen möchten (und vorausgesetzt, die Anzahl der Elemente in beiden Listen ist gleich), können Sie Zip verwenden .

var result = objects.Zip(ints, (o, i) => new { o, i})
                    .OrderBy(x => x.i)
                    .Select(x => x.o);

Ziemlich lesbar.

nawfal
quelle
Wichtiger Hinweis: Dazu muss die intsListe zunächst sortiert werden. Die akzeptierte Antwort nicht.
Thorarin
@ Thorarin nein ich denke. Warum sagst du das? Wir sortieren intstrotzdem, um die Sortierreihenfolge zu erhalten, daher müssen die Ints nicht erst bestellt werden.
Nawfal
@Thorarin, dann stimmt etwas anderes nicht. Ich bin mir über meinen Code sicher :)
Nawfal
1
Es löst definitiv nicht das Problem, das das OP beschreibt. Ihr Code wertet die ID-Eigenschaften der Objekte niemals aus. Wie kann es möglicherweise Sachen in die richtige Reihenfolge bringen?
Thorarin
@Thorarin Ich habe in meiner Antwort deutlich gemacht, dass Joineine Art von Problem gelöst wird. Zipist für etwas anderes. Der Titel lautet "Sortieren einer Sammlung in der Reihenfolge einer anderen Sammlung" und für die überwiegende Mehrheit würde dies bedeuten, was ich in der Antwort gewählt habe. Ich habe gerade eine alternative Antwort hinterlassen, die Menschen mit ähnlichen Problemen in Zukunft helfen könnte. Wenn die Sortierung auf der ID basiert, muss natürlich auch ein geeigneter Vergleicher angegeben werden (im OrderBy)
nawfal
4

Hier ist eine Erweiterungsmethode, die die Antwort von Simon D. für Listen eines beliebigen Typs kapselt .

public static IEnumerable<TResult> SortBy<TResult, TKey>(this IEnumerable<TResult> sortItems,
                                                         IEnumerable<TKey> sortKeys,
                                                         Func<TResult, TKey> matchFunc)
{
    return sortKeys.Join(sortItems,
                         k => k,
                         matchFunc,
                         (k, i) => i);
}

Verwendung ist so etwas wie:

var sorted = toSort.SortBy(sortKeys, i => i.Key);
gregsdennis
quelle
0

Eine mögliche Lösung:

myList = myList.OrderBy(x => Ids.IndexOf(x.Id)).ToList();

Hinweis: Verwenden Sie diese In-MemoryOption, wenn Sie mit Listen arbeiten, die nicht für den IQueryableTyp IQueryablefunktionieren , da sie keine Definition für enthältIndexOf

Mehdi Dehghani
quelle
-1

docs = docs.OrderBy(d => docsIds.IndexOf(d.Id)).ToList();

Sanish Thomas
quelle
2
Bitte posten Sie nicht nur Code als Antwort, sondern geben Sie auch eine Erklärung, was Ihr Code tut und wie er das Problem der Frage löst. Antworten mit einer Erklärung sind in der Regel hilfreicher und von besserer Qualität und ziehen eher positive Stimmen an.
Dima Kozhevin