Reputation: 123
I have an ArrayList
containing strings for example list 1 may be a list of names:
Bill, Bill, Bill, Henry, Sue, Sue
How do I use java streams to return the array as follows in ranked order (by occurrence)?
Bill, Bill, Bill, Sue, Sue, Henry
It would also be great to know how to display the final ranking of
Bill
, Sue
, Henry
. I have the following code:
System.out.println(
name.stream()
.sorted(Comparator.comparing(a->a))
.collect(Collectors.toList())
);
where name is the array. It works fine and arranges the array according to name but I also want to introduce ranking.
Upvotes: 3
Views: 1286
Reputation: 50716
Another solution is to group them, sort groups by size, then flat map:
names.stream()
.collect(Collectors.groupingBy(x -> x))
.values()
.stream()
.sorted(Comparator.comparingInt(List::size).reversed())
.flatMap(List::stream)
.collect(Collectors.toList())
Upvotes: 1
Reputation: 3043
here is how you could include ranking :
List<String> l = Arrays.asList("Bill", "Bill", "Bill", "Henry", "Sue", "Sue");
Map<String, Long> m = l.stream().collect(Collectors.groupingBy(x -> x, Collectors.counting()));
System.out.println(m);
the result is : {Sue=2, Bill=3, Henry=1}
Upvotes: 0
Reputation: 1147
This is not an answer on my own, i will just refactor shmosel's comment to take into account Eugene's remarks.
final List<String> names = <your names here>;
final Map<String, Long> namesByOccurence = names.stream()
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
final Comparator<String> byOccurrence = Comparator.comparing(namesByOccurence::get);
final String[] res = names.stream()
.sorted(byOccurrence.reversed())
.toArray(String[]::new);
Upvotes: 1
Reputation: 120848
First it's a little bit unclear what you actually want to achieve: a List<List<String>>
or List<String[]>
or a String[]
...
One one hand you want Bill, Bill, Bill, Sue, Sue, Henry
, but if your list is {Bill, Bill, Bill, Sue, Henry, Henry}; {Bill, Gene, Sue}
what would your result be in such case? A single String[]
or .... what exactly? You also mention that how to display the final ranking of Bill, Sue, Henry, which obviously means something else entirely...
In any case:
Shmosel solution in comments is indeed very nice! (but assume two things, that your list is editable, thus you can sort it and that you want a sorted List as opposed to an array). And you can't refactor that to a single stream operation that returns an array, because that would mean consuming the stream twice... which you can't.
You can do it via two operations:
List<String> flat = all.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
String[] result = flat.stream()
.sorted(Comparator.comparing(x -> Collections.frequency(flat, x)).reversed())
.toArray(String[]::new);
This will for the input that I gave above will be:
[Bill, Bill, Bill, Bill, Henry, Henry, Sue, Sue, Gene]
If you want to sort each list, then you could use:
List<List<String>> res = all.stream()
.map(x -> x.stream()
.sorted(Comparator.comparing(y -> Collections.frequency(x, y)).reversed())
.collect(Collectors.toList()))
.collect(Collectors.toList());
And the result will be:
[[Bill, Bill, Bill, Henry, Henry, Sue], [Bill, Gene, Sue]]
Upvotes: 1