2017-10-01 2 views
0

J'ai un vecteur d'une structure personnalisée et une liste d'attributs à utiliser pour ordonner ce vecteur en priorité décroissante. Par exemple:Trier un vecteur avec un comparateur qui change dynamiquement son comportement

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(); 

Je veux que le vecteur à commander comme indiqué par order_vec. Dans cet exemple, il doit d'abord être ordonné par le nom de l'artiste, quand il est égal, il devrait être ordonné par le titre. Je ne veux pas coder en dur cette commande car order_vec change dynamiquement.

J'ai trouvé Vec::sort_by qui prend une fonction de comparaison. Comment puis-je générer dynamiquement cette fonction? Y at-il un moyen de le faire sans sort_by?

+1

Il existe plusieurs parties différentes de votre problème. Vous avez apparemment déjà découvert 'sort_by()': il vous permet de passer un comparateur personnalisé pour faire des comparaisons entre les éléments. Mais alors vous devez analyser une chaîne spécifiant comment le vecteur doit être trié, alors vous devez l'utiliser pour faire le tri réel. Comme il y a tellement de choses, cette question n'est pas assez focalisée. Alors s'il vous plaît dites-nous: quel est exactement votre problème maintenant? –

+0

Parsing the String n'est pas un problème, pensé à le diviser en un vec de chaînes et se traiter individuellement. Le problème est la deuxième partie: générer dynamiquement la fonction de comparaison. La chaîne sort_string peut contenir n'importe quel Attribut à trier avec une priorité décroissante. L'ordre de ceux-ci est également dynamique. Donc la Funktion de comparaison doit être créée dynamiquement et je ne sais pas comment faire. Peut-être qu'il y a une autre façon sans utiliser la construction dans les méthodes de tri? – ZeroTek

Répondre

6

Comment générer dynamiquement cette fonction

Vous n'avez pas. Vous avez une fermeture spécifique qui a un comportement dynamique en son sein.

Ici, nous avons une liste de sortes à appliquer. Lorsque nous devons comparer deux éléments, nous parcourons la liste. Nous utilisons Ordering::then_with pour appliquer uniquement la comparaison lorsque la comparaison précédente était Equal:

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), 
       } 
      }) 
     }) 
    }) 
} 

J'ai utilisé un ENUM pour les champs parce que je ne voulais pas faire face à ce qu'il faut faire quand l'une des sortes est un champ inconnu .

+0

Bonne réponse. Je ne connaissais pas 'Ordering :: then_width', et j'aime le lien avec' Iterator :: fold'. – user4815162342