dooberrywotsit
dooberrywotsit

Reputation: 123

using java streams to rank data in an array list

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

Answers (4)

shmosel
shmosel

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

aName
aName

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

marsouf
marsouf

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

Eugene
Eugene

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

Related Questions