2017-07-05 9 views
6

Ich möchte die Frequenzen der Zahlen in einem TreeMap mit den Frequenzen als die Schlüssel und die Zahlen, die diese Frequenz in einem ArrayList haben.Inverted Collectors.toMap zu einer ArrayList hinzufügen

Ich habe zwei Probleme:

1) Ich bin eine „nicht-statischen Methoden kann nicht von einem statischen Kontext referenziert wird“ immer Fehler im ersten Parameter (AFAIK der Stream verweist auf ein Objekt - was ist los?)

2) Es gibt 4 Parameter für Collectors.toMap() - es scheint wie Parameter 4 erfordert Initialisierung mit einer neuen TreeMap>, Parameter 2 könnte eine ArrayList add() -Funktion sein und Parameter 3 könnte Null (vielleicht) . Wie wird das gemacht?

import java.util.*; 
import java.util.function.Function; 
import java.util.stream.Collectors; 

public class Main { 

    public static void main(String[] args) { 

     List<Integer> array = Arrays.asList(1, 2, 4, 5, 6, 4, 8, 4, 2, 3); 

     Map<Integer, Long> m = array.stream() 
      .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); 

     System.out.println(m); 

     TreeMap<Long, List<Integer>> tm = m.entrySet().stream() 
      .collect(Collectors.toMap(Map.Entry::getValue, ...)); 

Im Moment kann ich nicht sehen, verwenden, wie von https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html zu bekommen, wo ich sein muss.

Antwort

6

Sie sind fast richtig in Ihrer Argumentation ... Nur dass das 3. Argument ist, wo Sie Ihre Werte für den gleichen Schlüssel zusammenführen - so dass Sie es nicht weglassen können.

TreeMap<Long, List<Integer>> tm = m.entrySet().stream() 
      .collect(Collectors.toMap(
        Entry::getValue, 
        x -> { 
         List<Integer> list = new ArrayList<>(); 
         list.add(x.getKey()); 
         return list; 
        }, 
        (left, right) -> { 
        left.addAll(right); 
        return left; 
        }, 
        TreeMap::new)); 
+0

ich die bearbeitete Array.asList Zeile, da es von der vorliegenden Frage ablenkt. –

+0

@JohnEstess ausgezeichnet, ich habe die Antwort editieren, um das auch zu entfernen – Eugene

+0

Sie können ein paar Zeilen speichern, indem Sie als das zweite Argument zu 'toMap' folgendes:' x -> new ArrayList <> (singletonList (x.getKey ())) '. – Lii

6

Ich denke Collectors.groupingBy macht mehr Sinn als Collectors.toMap zu erreichen, was Sie suchen:

Map<Long, List<Integer>> tm = 
    m.entrySet() 
    .stream() 
    .collect(Collectors.groupingBy(Map.Entry::getValue, // group the entries by the 
                 // value (the frequency) 
            TreeMap::new, // generate a TreeMap 
            Collectors.mapping (Map.Entry::getKey, 
                 Collectors.toList()))); // the 
                 // value of the output TreeMap 
                 // should be a List of the 
                 // original keys 

Sie können mit Collectors.toCollection(ArrayList::new)Collectors.toList() ersetzen, um sicherzustellen, dass die Werte des Ausgangs Map sind ArrayList s (obwohl die aktuelle Implementierung von toList() bereits in java.util.ArrayList Instanzen führt).

Für Ihre Abtastwerteingang, dies erzeugt die folgende TreeMap:

{1=[1, 3, 5, 6, 8], 2=[2], 3=[4]} 
7

Ich würde nicht Ströme verwenden, um die invertierte Karte zu erstellen. Stattdessen würde ich nur tun:

Map<Long, List<Integer>> tm = new TreeMap<>(); 
m.forEach((num, freq) -> tm.computeIfAbsent(freq, k -> new ArrayList<>()).add(num)); 

System.out.println(tm); // {1=[1, 3, 5, 6, 8], 2=[2], 3=[4]} 

Da der Code die invertierte Karte zu erstellen ist kurz, Sie Collectors.collectingAndThen nutzen könnten sowohl die Frequenzen und umgekehrt Karte in einem Schritt zu erstellen:

TreeMap<Long, List<Integer>> invertedFrequenciesMap = array.stream() 
    .collect(Collectors.collectingAndThen(
     Collectors.groupingBy(Function.identity(), Collectors.counting()), 
     map -> { 
      TreeMap<Long, List<Integer>> tm = new TreeMap<>(); 
      map.forEach((num, freq) -> 
        tm.computeIfAbsent(freq, k -> new ArrayList<>()).add(num)); 
      return tm; 
     })); 
+2

definitiv +1 (wollte das gleiche zuerst zeigen, aber das OP fragte nach, wie man mit 'toMap' ...) – Eugene

+1

alle Antworten oben habe ich up-vote, so haben Sie auch meine. :) –

Verwandte Themen