Split map into two lists

I have an Map<String,Integer> and it's sorted by value like this:

set = map.entrySet();
list = new ArrayList<Map.Entry<String, Integer»(set);
Collections.sort( list, (o1, o2) -> (o2.getValue()).compareTo( o1.getValue() ));

I already have a sorted integer list from that map:

word_used = new ArrayList<Integer>(map.values() 
.stream() 
.sorted() 
.collect(Collectors.toList())); 
Collections.reverse(word_used); 

But how I can get a String list, which will be sorted equal to Map (by value)?

I mean if I have a map with items:

map.put("eggs",1500); 
map.put("echo",150); 
map.put("foo",320); 
map.put("smt",50); 

and sort it like:

eggs : 1500 
foo : 320 
echo : 150 
smt : 50 

I need to get 2 lists:

eggs 
foo 
echo 
smt

and

1500 
320 
150 
50

Upvotes: 4

Views: 3943

Answers (4)

Arnab Datta
Arnab Datta

Reputation: 5256

You can use a TreeMap with a comparator that compares values rather than keys, and then just call keys() and values() on that.

See: https://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727057

You can add projection to your streams using map(), like this:

List<String> word_used = map.entrySet() 
        .stream() 
        .sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed())
        .map(Map.Entry<String,Integer>::getKey)
        .collect(Collectors.toList());

List<Integer> ints_used = map.entrySet() 
        .stream() 
        .sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed())
        .map(Map.Entry<String,Integer>::getValue)
        .collect(Collectors.toList());

Demo 1

Note that this approach sorts twice. You can capture the entries once, and then project from that temporary list, like this:

List<Map.Entry<String,Integer>> sortedList = map
        .entrySet() 
        .stream() 
        .sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed())
        .collect(Collectors.toList());

List<String> word_used = sortedList
        .stream()
        .map(Map.Entry<String,Integer>::getKey)
        .collect(Collectors.toList());

List<Integer> ints_used = sortedList
        .stream()
        .map(Map.Entry<String,Integer>::getValue)
        .collect(Collectors.toList());

Demo 2

Upvotes: 3

Hank D
Hank D

Reputation: 6491

One might sort and iterate only once using this method:

    List<String> word_used = new ArrayList<String>();
    List<Integer> ints_used = map.entrySet().stream() 
        .sorted(Comparator.comparing(Map.Entry<String,Integer>::getValue).reversed())
        .peek(e -> word_used.add(e.getKey()))
        .map(Map.Entry::getValue)
        .collect(Collectors.toList());

Upvotes: 0

John Bollinger
John Bollinger

Reputation: 181734

You already have a List (referenced by variable list) of the map Entrys, sorted by value into the order you describe. You can just construct new, separate Lists of the keys and values from those objects. The non-stream version of that might be:

List<String> words = new ArrayList<>();
List<Integer> values = new ArrayList<>();

for (Map.Entry<String, Integer> entry : list) {
    words.add(entry.getKey());
    values.add(entry.getValue());
}

Upvotes: 2

Related Questions