Month: December 2017

Sort Array of String by their counts in Java 8

Posted on

Here, we will see how to sort an array base on elements occurrences in Java 8.

Suppose we got a city list containing duplicate city as well like below.

"Delhi,Agra,Bihar,UP,Delhi,Agra,Bihar,UP,Delhi,Bihar,Delhi,Agra,Delhi";

First, we have to do aggregation on city name by applying groupBy function, count their occurrence and return a Map.

 String cities = "Delhi,Agra,Bihar,UP,Delhi,Agra,Bihar,UP,Delhi,Bihar,Delhi,Agra,Delhi";
        
 TreeMap<String, Long> groupByCitiesMap = Stream.of(cities.split(","))
                .collect(Collectors.groupingBy(s -> s, TreeMap::new, Collectors.counting()));
 System.out.println(groupByCitiesMap);

This will return a TreeMap of sorted by City (natural sorting) that containing unique city name as key and their counts as in value.

{Agra=3, Bihar=3, Delhi=5, Uttar Pradesh=2}

OR

We can do it old fashion without using Stream.

TreeMap<String, CityReport> treeMap = new TreeMap();
for (String city : cities.split(",")) {
    CityReport cityReport = new CityReport(city);
    if (treeMap.containsKey(city)) {
        treeMap.computeIfPresent(city, (key, val) -> {val.counter+=1;return val;});
    } else {
        treeMap.put(city, cityReport);
    }
}

This will return a Map that containing unique city name as key and CityReport as value containing city name and count.

{Agra=CityReport{city=’Agra’, counter=3}, Bihar=CityReport{city=’Bihar’, counter=3}, Delhi=CityReport{city=’Delhi’, counter=5}, UP=CityReport{city=’UP’, counter=2}}

and Finally, need to be sorted out by City count and City name. so here we do so…

List<CityReport> sortedCityReport = treeMap.values().stream().sorted(new ComparatorFilter(new ComparatorByNumber(),new ComparatorByName())).collect(Collectors.toList());

System.out.println("Sort By Count first then City Name "+ sortedCityReport);

Output:

Sort By Count first then City Name [CityReport{city=’UP’, counter=2}, CityReport{city=’Agra’, counter=3}, CityReport{city=’Bihar’, counter=3}, CityReport{city=’Delhi’, counter=5}]

Rest of code is below:-

ComparatorFilter.Java :- Sorting by chain of comparator ( by count and name )  over the Collection.

static class ComparatorFilter implements Comparator<CityReport> {

    private final List<Comparator<CityReport>> comparators;

    ComparatorFilter(Comparator<CityReport>... comparators) {
        this.comparators = Arrays.asList(comparators);
    }

    @Override
    public int compare(CityReport o1, CityReport o2) {
        for (Comparator c : this.comparators) {
            int val = c.compare(o1, o2);
            if (val != 0) {
                return val;
            }
        }
        return 0;
    }
}

ComparatorByName.Java – Sorting by City Name

static class ComparatorByName implements Comparator<CityReport> {

    @Override
    public int compare(CityReport o1, CityReport o2) {
        return o1.city.compareTo(o2.city);
    }
}

ComparatorByNumber.Java – sorting by count number.

static class ComparatorByNumber implements Comparator<CityReport> {

    @Override
    public int compare(CityReport o1, CityReport o2) {
        return (int) (o1.counter - o2.counter);
    }
}

CityReport Model Class –


class CityReport {
String city;
Long counter;

public CityReport(String city) {
    this.city = city;
    this.counter = 1L;
}


@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    CityReport that = (CityReport) o;
    return Objects.equals(city, that.city);
}

@Override
public int hashCode() {

    return Objects.hash(city);
}

@Override
public String toString() {
    return "CityReport{" +
            "city='" + city + '\'' +
            ", counter=" + counter +
            '}';
}
}