2017-12-20 6 views
-2

Als Eingang, ich habe Liste der Objekte hat jeder Objektname und Karte:Sortieren Java Karte basierend auf Werten in einer anderen Karte

1) 
    Name: m1 

    Map: {"c1": 3, 
"c2": 24 
"c3": 12} 

2) Name: m2 

Map: {"c1": "A", 
"c2": "B", 
"c3": "C"} 

3) Name: m3 

Map: {"c1": 3.4, 
"c2": 4.6, 
"c3": 12.3} 

Was ich als Ausgang brauche, ich brauche alle 3 zu sortieren Karten basierend auf Werten in der Karte mit dem Namen m1.

Also zuerst möchte ich in absteigender Aufträge Karte für Objekt # 1 (m1) von Werten sortieren (ich hier verwenden LinedHashMap können):

{"c1": 3, "c2": 24, "c3": 12} => {"c2": 24, "c3": 12, "c1": 3} 

Und jetzt möchte ich Elemente in Karte für Objekt # 2 und Karte für Objekt # 3, auch in den gleichen Tastenordnungen sortiert - C2, C3, C1. Also im Grunde möchte ich 2 Karten reorder so, dass Reihenfolge ist C2, C3, C1 (die gleiche Reihenfolge wie in m1), und NICHT C1, C2, C3.

Wie kann ich es am elegantesten tun? Ich habe einige Lösungen - aber sie sind chaotisch und haben viele zusätzliche Schritte.

Wenn es wichtig ist: diese Liste wird immer nur 3 Objekte haben. Anzahl der Elemente in Map kann unterschiedlich sein, aber Schlüssel in Karten werden immer über 3 Karten hinweg gleich sein.

+2

@ram. 'TreeMap' kann sortiert werden. – tsolakp

+1

@tsolakp Nein, kann es nicht. Es ist * bereits auf seinen Schlüsseln sortiert. Sie können Karten nicht nach ihren Werten sortieren. – EJP

Antwort

1

So können Sie eine Map nach Wert sortieren, vielleicht durch Lesen dieser Antwort: Sort a Map by values (Java), wo die Java 8-Version von die Antwort lautet:

m1sorted = m1.entrySet() 
      .stream() 
      .sorted(Map.Entry.comparingByValue(Collections.reverseOrder())) 
      .collect(Collectors.toMap(
       Map.Entry::getKey, 
       Map.Entry::getValue, 
       (e1, e2) -> e1, 
       LinkedHashMap::new 
      )); 

So wie Sie sortieren m2 und m3 durch die Werte von m1?

Einfach: Sie liefern eine Comparator an sorted(), die die Werte vergleicht, z.

.sorted(Comparator.comparing(e -> m1.get(e.getKey())).reversed()) 

können Sie haben ausdrücklich die Art der e angeben, da die Inferenzmaschine verloren gehen kann: comparing((Entry<String, String> e) ->

Wenn Sie nicht Comparator.comparing() mögen und reversed(), und die Folgerung Ausgabe, können Sie einfach nutzen ein Lambda.

Hier ist der gesamte Code, als Proof of Concept:

Map<String, Integer> m1 = new HashMap<>(); 
m1.put("c1", 3); 
m1.put("c2", 24); 
m1.put("c3", 12); 

Map<String, String> m2 = new HashMap<>(); 
m2.put("c1", "A"); 
m2.put("c2", "B"); 
m2.put("c3", "C"); 

Map<String, Double> m3 = new HashMap<>(); 
m3.put("c1", 3.4); 
m3.put("c2", 4.6); 
m3.put("c3", 12.3); 
Map<String, Integer> m1s = 
     m1.entrySet() 
      .stream() 
      .sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue())) 
      .collect(Collectors.toMap(Map.Entry::getKey, 
            Map.Entry::getValue, 
            (e1, e2) -> e1, 
            LinkedHashMap::new)); 

Map<String, String> m2s = 
     m2.entrySet() 
      .stream() 
      .sorted((e1, e2) -> Integer.compare(m1.get(e2.getKey()), m1.get(e1.getKey()))) 
      .collect(Collectors.toMap(Map.Entry::getKey, 
            Map.Entry::getValue, 
            (e1, e2) -> e1, 
            LinkedHashMap::new)); 

Map<String, Double> m3s = 
     m3.entrySet() 
      .stream() 
      .sorted((e1, e2) -> Integer.compare(m1.get(e2.getKey()), m1.get(e1.getKey()))) 
      .collect(Collectors.toMap(Map.Entry::getKey, 
            Map.Entry::getValue, 
            (e1, e2) -> e1, 
            LinkedHashMap::new)); 
System.out.println(m1s); 
System.out.println(m2s); 
System.out.println(m3s); 

Ausgabe

{c2=24, c3=12, c1=3} 
{c2=B, c3=C, c1=A} 
{c2=4.6, c3=12.3, c1=3.4} 

Beachten Sie, wie e2 und e1 werden in den Lambdas umgekehrt, um eine absteigende Reihenfolge zu bewirken.

Natürlich wäre es viel besser, die Objektorientierten Features von Java zu verwenden und nur einen Map zu Objekten mit drei Feldern für die Werte zu haben.

+0

Das ist alles sehr gut, aber es sortiert die Map nicht wirklich. – EJP

+1

@EJP Es sortiert tatsächlich die Karte. Natürlich müssen Sie die Sortierung jedes Mal wiederholen, wenn Sie einen Wert hinzufügen/aktualisieren, aber dies ist das Ergebnis, das Sie am nächsten zu einer nach Wert sortierten Map erhalten. Niemals gesagt, es war effizient, aber es ist, was es ist ... – Andreas

+0

@Andreas Vielen Dank für Ihre Hilfe. Ich mag Ihren Ansatz, aber ich denke, dass diese Zeile nicht genau das ist, was ich in m2s und m3s erwartet habe: **. Sortiert ((e1, e2) -> Integer.compare (m1.get (e2.getKey()) , m1.get (e1.getKey()))) ** Es scheint wie es sortiert m2s und m3s Karten basierend auf Werten der m1s Karte, und nicht KEYS. Ich brauche es nach Schlüsseln von m1s map zu sortieren. Wie erstellt man einen solchen Komparator? – Bilberryfm

Verwandte Themen