2016-11-01 7 views
3

Wie kann ich beim Sortieren mit mehreren Schlüsseln die Reihenfolge eines einzelnen Schlüssels umkehren? Zum Beispiel:Umgekehrter spezifischer Schlüssel beim Sortieren mit mehreren Schlüsseln

vec.sort_by_key(|k| (foo(k).reverse(), bar(k))); 
+0

Mit mehreren Schlüsseln meinst du mehrere Sortierkriterien (jede mit absteigender Priorität)? –

+0

@ E_net4 Ja. Wenn das Tupel (x, y) war, dann sortiere mit x und brich die Bindungen mit y. Außer in diesem Fall möchte ich eine absteigende Reihenfolge für x. – HiDefender

+0

Ihr Beispiel funktioniert gut für die entsprechenden Implementierungen von 'foo',' reverse' und 'bar'. – Shepmaster

Antwort

4

können Sie sort_by mit Ordering::reverse gepaart anstelle von sort_by_key.

use std::cmp::Ordering; 

#[derive(Debug)] 
struct Foo(&'static str, u8); 

impl Foo { 
    fn name(&self) -> &str { self.0 } 
    fn len(&self) -> u8 { self.1 } 
} 

fn main() { 
    let mut vec = vec![Foo("alpha", 1), Foo("beta", 2), Foo("beta", 1)]; 

    vec.sort_by(|a, b| { 
     match a.name().cmp(b.name()).reverse() { 
      Ordering::Equal => a.len().cmp(&b.len()), 
      other => other, 
     } 
    }); 

    println!("{:?}", vec); 
} 

Diese Art in umgekehrter alphabetischer Reihenfolge, sind in aufsteigender numerischer Reihenfolge dann Bindungen sortiert:

[Foo("beta", 1), Foo("beta", 2), Foo("alpha", 1)] 

Wenn RFC 1677 akzeptiert und umgesetzt wird, dies aussehen könnte:

vec.sort_by(|a, b| { 
    a.name().cmp(b.name()).reverse() 
     .then(a.len().cmp(&b.len())) 
}); 

Wenn Sie haben etwas, das natürlich negiert/invertiert werden kann, können Sie simply negate the key.

+0

Danke. So ist 'sort_by' mächtiger als' sort_by_key': 'sort_by' kann alles, was' sort_by_key' kann tun, aber 'sort_by_key' kann nicht alles, was' sort_by' kann. Was ist der Vorteil von 'sort_by_key'? – HiDefender

+0

@HiDefender ist es viel einfacher für extrem häufige Fälle. Es kann sogar für Ihren Fall funktionieren, wie ich in der anderen Frage verlinkt habe. – Shepmaster

+0

Noch einmal, danke. Zwei weitere Fragen: 1. Übergeben Sie '& b.len()' im zweiten Vergleich. Warum unterstützt cmp() nicht die Weitergabe von Eigentumsrechten, nur die Ausleihe? 2. Ist es notwendig, dass Ihre Struktur "[derived (Debug)]" hat? Konnte es ohne das nicht sortiert werden? – HiDefender

2

Hier ist eine ähnliche Herangehensweise an das Problem: eine Funktion für die Verkettung mehrerer Ordnungen erstellen:

/// chain two orderings: the first one gets more priority 
fn chain_ordering(o1: Ordering, o2: Ordering) -> Ordering { 
    match o1 { 
     Ordering::Equal => o2, 
     _ => o1, 
    } 
} 

Dann sort_by verwenden, möglicherweise mit Pattern-Matching, die Reihenfolge der einzelnen Tasten zu erzeugen:

#[derive(Debug, PartialEq)] 
struct HeroSkill(&'static str, &'static str); 

fn main() { 
    // a vector of hero names and super powers 
    let mut v = vec![ 
     HeroSkill("Bob", "X"), 
     HeroSkill("Bob", "Y"), 
     HeroSkill("Alice", "X") 
    ]; 

    // sort by name, then by super power, where Y is more powerful than X 
    v.sort_by(|&HeroSkill(name1, power1), &HeroSkill(name2, power2)| { 
     chain_ordering(name1.cmp(name2), power1.cmp(power2).reverse()) 
    }); 

    assert_eq!(v, vec![ 
     HeroSkill("Alice", "X"), 
     HeroSkill("Bob", "Y"), 
     HeroSkill("Bob", "X") 
    ]); 
} 

Playground

3

Die revord Kiste (documentation) bietet eine Struktur, RevOrd, das einen Wert umschließt und PartialOrd und Ord implementiert, indem partial_cmp und cmp mit vertauschten Argumenten aufgerufen werden, um die umgekehrte Reihenfolge zurückzugeben. Umbrechen Sie einfach den Schlüssel, um in absteigender Reihenfolge in einer RevOrd Struktur zu sortieren.

vec.sort_by_key(|k| (RevOrd(foo(k)), bar(k))); 
Verwandte Themen