简体   繁体   中英

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.

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

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

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())

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}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM