2017-07-05 37 views
6

Chciałbym umieścić częstotliwości numerów w TreeMap z częstotliwościami jako klucze i numery, które mają tę częstotliwość w ArrayList.Odwrócony Collectors.toMap, aby dodać do ArrayList

mam dwa problemy:

1) Dostaję „metod non-statyczne nie można odwoływać się od statycznego kontekstowego” błąd w pierwszym parametrze (AFAIK strumień odwołuje obiekt - co się dzieje?)

2) Istnieją 4 parametry dla Collectors.toMap() - wydaje się, że parametr 4 wymaga inicjalizacji z nową mapą drzewa>, parametrem 2 może być funkcja add() ArrayList, a parametr 3 może mieć wartość null (być może) . Jak to się robi?

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, ...)); 

W tej chwili nie mogę wykorzystać zobaczyć jak dostać się z https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html gdzie muszę być.

Odpowiedz

6

Masz rację w swoim rozumowaniu ... Tyle tylko, że trzeci argument to miejsce, w którym łączysz swoje wartości dla tego samego klucza - więc nie możesz tego pominąć.

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

I redagował Linia Array.asList, ponieważ odwraca uwagę od danego pytania. –

+0

@JohnEstess doskonała, edytowałem odpowiedź, aby ją usunąć, także – Eugene

+0

Możesz zapisać kilka wierszy, mając jako drugi argument 'toMap' następujące:' x -> new ArrayList <> (singletonList (x.getKey ())) '. – Lii

6

myślę Collectors.groupingBy większy sens niż Collectors.toMap aby osiągnąć to, czego szukasz:

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 

Można zastąpić Collectors.toList() z Collectors.toCollection(ArrayList::new) aby upewnić się, że wartości na wyjściu MapArrayList s (chociaż obecna implementacja toList() już skutkuje wystąpieniami java.util.ArrayList).

za wkład próbki, to produkuje następujące TreeMap:

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

nie będę używać strumieni stworzyć odwróconą mapę. Zamiast tego po prostu zrobić:

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]} 

jako kod, aby utworzyć odwrócony mapa jest krótki, można użyć Collectors.collectingAndThen do tworzenia zarówno częstotliwości i rewersu mapy w jednym kroku:

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

zdecydowanie +1 (chciałem pokazać to samo na początku, ale OP zapytał o to, jak zrobić z "toMap" ...) – Eugene

+1

wszystkie powyższe odpowiedzi mam do góry, więc też masz moje. :) –