2017-10-01 1 views
0

Ich habe einen Vektor einer benutzerdefinierten Struktur und eine Liste von Attributen, um diesen Vektor in absteigender Priorität zu ordnen. Zum Beispiel:Sortiere einen Vektor mit einem Vergleicher, der sein Verhalten dynamisch ändert

struct TheStruct { 
    artist: String, 
    title: String, 
    date: String, 
} 

let order_vec: Vec<String> = vec!["artist".to_string(),"title".to_string(),"date".to_string()]; 
let item_vec: Vec<TheStruct> = Vec::new(); 

Ich möchte der Vektor bestellt werden, wie durch order_vec gegeben. In diesem Beispiel sollte es zuerst nach dem Künstlernamen geordnet werden, wenn dies gleich ist, sollte es durch den Titel geordnet werden. Ich möchte diese Reihenfolge nicht hart codieren, da sich order_vec dynamisch ändert.

Ich fand Vec::sort_by, die eine Vergleichsfunktion benötigt. Wie erzeuge ich diese Funktion dynamisch? Gibt es eine Möglichkeit, dies ohne sort_by zu tun?

+1

Es gibt einige verschiedene Teile Ihres Problems. Sie haben anscheinend schon von 'sort_by()' erfahren: Sie können einen benutzerdefinierten Komparator übergeben, um Vergleiche zwischen Elementen durchzuführen. Aber dann müssen Sie eine Zeichenkette analysieren, die angibt, wie der Vektor sortiert werden soll. Dann müssen Sie die eigentliche Sortierung durchführen. Da es so viele Dinge gibt, ist diese Frage nicht ausreichend fokussiert. Also sag uns bitte: was genau ist dein Problem jetzt? –

+0

Das Parsen der Saite ist kein Problem, ich denke darüber nach, es in ein Vec von Saiten aufzuteilen und jedes einzeln zu bearbeiten. Das Problem ist der zweite Teil: dynamisch generieren Sie die Vergleichsfunktion. Der sort_string kann ein oder kein Attribut enthalten, nach dem mit abnehmender Priorität sortiert wird. Die Reihenfolge ist auch dynamisch. Also muss die Vergleichsfunktion dynamisch erstellt werden und ich weiß nicht wie das geht. Vielleicht gibt es einen anderen Weg ohne eingebaute Sortiermethoden? – ZeroTek

Antwort

6

Wie dynamisch ich

Sie dies nicht tun, diese Funktion erzeugen. Sie haben eine bestimmte Schließung, die ein dynamisches Verhalten in sich hat.

Hier haben wir eine Liste von Arten zutreffen. Wenn wir zwei Elemente vergleichen müssen, durchlaufen wir die Liste. Wir verwenden Ordering::then_with nur den Vergleich zu gelten, wenn der vorherige Vergleich Equal war:

use std::cmp::Ordering; 

#[derive(Debug, Copy, Clone)] 
enum Field { 
    Artist, 
    Title, 
    Date, 
} 

struct TheStruct { 
    artist: String, 
    title: String, 
    date: String, 
} 

fn main() { 
    let mut items: Vec<TheStruct> = vec![]; 

    use Field::*; 
    let orders = vec![Artist, Title]; 

    items.sort_by(|a, b| { 
     orders.iter().fold(Ordering::Equal, |acc, &field| { 
      acc.then_with(|| { 
       match field { 
        Artist => a.artist.cmp(&b.artist), 
        Title => a.title.cmp(&b.title), 
        Date => a.date.cmp(&b.date), 
       } 
      }) 
     }) 
    }) 
} 

ich eine Enumeration für die Felder verwendet, weil ich nicht behandeln wollte, was zu tun ist, wenn eine der Sorten ein unbekanntes Feld .

+0

Schöne Antwort. Ich kannte "Ordering :: then_width" nicht, und ich mag die Verbindung mit "Iterator :: fold". – user4815162342

Verwandte Themen