How can I get the count of most duplicated value in a list after sorting it alphabetically?

Viewed 121

What is the easiest way to get the most duplicated value in a list and sorted in descending order... for example:

List<String> list = new ArrayList<>(List.of("Renault","BMW","Renault","Renault","Toyota","Rexon","BMW","Opel","Rexon","Rexon"));

` "renault" & "rexon" are most duplicated and if sorted in descending order alphabetically I would like to get the rexon.

6 Answers

I think one of the most readable and elegant way would be to use the Streams API

strings.stream()
       .collect(Collectors.groupingBy(x -> x, Collectors.counting()))
       .entrySet().stream()
       .max(Comparator.comparingLong((ToLongFunction<Map.Entry<String, Long>>) Map.Entry::getValue).thenComparing(Map.Entry::getKey))
       .map(Map.Entry::getKey)
       .ifPresent(System.out::println);
  1. Create a map of names with their corresponding number of occurrences.
  2. Get names and sort them in descending order.
  3. Print the first name that has the highest number of occurrences.
class Scratch {
    public static void main(String[] args) {
        List<String> list = List.of("Renault","BMW","Renault","Renault","Toyota","Rexon","BMW","Opel","Rexon","Rexon");
        Map<String, Integer> duplicates = new HashMap<>();
        
        // 1. Create a map of names with their corresponding
        // number of occurrences.
        for (String s: list) {
            duplicates.merge(s, 1, Integer::sum);
        }
        
        // 2. Get names and sort them in descending order.
        List<String> newList = new ArrayList<String>(duplicates.keySet());
        newList.sort(Collections.reverseOrder());
        
        // 3. Print the first name that has the highest number of
        // occurrences.
        Integer max = Collections.max(duplicates.values());
        newList.stream().filter(name -> duplicates.get(name).equals(max))
                        .findFirst()
                        .ifPresent(System.out::println);
    }
}

After some time this is what I came with (I only tested it with your example and it worked):

public class Duplicated {
public static String MostDuplicated(String[] a) {
int dup = 0;
int position = -1;
int maxDup = 0;
for(int i = 0; i < a.length; i++) { //for every position
   
    for(int j = 0; j < a.length; j++){ //compare it to all
        if(a[i].equals(a[j])) { dup++; }  // and count how many time is duplicated
    }
    
    if (dup > maxDup) { maxDup = dup; position = i;} 

//if the number of duplications 
//is greater than the maximum you have got so far, save this position.

    else if (dup == maxDup) { 
        if( a[i].compareTo(a[position]) > 0 ){ position = i; }

//if its the same, keep the position of the alphabetical last
// (if u want the alphabetical first, just change the "<" to ">") 
    }
}
      
   
return a[position];  //return the position you saved

}
}

Actually, I found a solution which works:

public static void main(String[] args) {

    List<String> list = new ArrayList<>(List.of("Renault", "BMW", "BMW", "Renault", "Renault", "Toyota",
            "Rexon", "BMW", "Opel", "Rexon", "Rexon"));
    Map<String, Integer> soldProducts = new HashMap<>();
    for (String s : list) {
        soldProducts.put(s, soldProducts.getOrDefault(s, 0) + 1);
    }
    LinkedHashMap<String, Integer> sortedMap = soldProducts.entrySet()
            .stream()
            .sorted(VALUE_COMPARATOR.thenComparing(KEY_COMPARATOR_REVERSED))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2, LinkedHashMap::new));
    String result = "";
    for (Map.Entry<String, Integer> s : sortedMap.entrySet()) {
        result = s.getKey();
    }
    System.out.println(result);
}

static final Comparator<Map.Entry<String, Integer>> KEY_COMPARATOR_REVERSED =
        Map.Entry.comparingByKey(Comparator.naturalOrder());

static final Comparator<Map.Entry<String, Integer>> VALUE_COMPARATOR =
        Map.Entry.comparingByValue();

The fast algorithm takes advantage of the fact that the list is sorted and finds the list with the most duplicates in O(n), with n being the size of the list. Since the list is sorted the duplicates will be together in consecutive positions:

private static String getMostDuplicates(List<String> list) {
    if(!list.isEmpty()) {
        list.sort(Comparator.reverseOrder());
        String prev = list.get(0);
        String found_max = prev;
        int max_dup = 1;
        int curr_max_dup = 0;
        for (String s : list) {
            if (!s.equals(prev)) {
                if (curr_max_dup > max_dup) {
                    max_dup = curr_max_dup;
                    found_max = prev;
                }
                curr_max_dup = 0;
            }
            curr_max_dup++;
            prev = s;
        }
        return found_max;
    }
    return "";
}

Explanation:

We iterate through the list and keep track of the maximum of duplicates found so far and the previous element. If the current element is the same as the previous one we increment the number of duplicates found so far. Otherwise, we check if the number of duplicates is the bigger than the previous maximum of duplicates found. If it is we update accordingly

A complete running example:

public class Duplicates {

        private static String getMostDuplicates(List<String> list) {
            if(!list.isEmpty()) {
                list.sort(Comparator.reverseOrder());
                String prev = list.get(0);
                String found_max = prev;
                int max_dup = 1;
                int curr_max_dup = 0;
                for (String s : list) {
                    if (!s.equals(prev)) {
                        if (curr_max_dup > max_dup) {
                            max_dup = curr_max_dup;
                            found_max = prev;
                        }
                        curr_max_dup = 0;
                    }
                    curr_max_dup++;
                    prev = s;
                }
                return found_max;
            }
            return "";
        }
    
        public static void main(String[] args) {
            List<String> list = new ArrayList<>(List.of("Renault","BMW","Renault","Renault","Toyota","Rexon","BMW","Opel","Rexon","Rexon"));
            String duplicates = getMostDuplicates(list);
            System.out.println("----- Test 1 -----");
            System.out.println(duplicates);
    
            list = new ArrayList<>(List.of("Renault","BMW"));
            duplicates = getMostDuplicates(list);
            System.out.println("----- Test 2 -----");
            System.out.println(duplicates);
    
            list = new ArrayList<>(List.of("Renault"));
            duplicates = getMostDuplicates(list);
            System.out.println("----- Test 3 -----");
            System.out.println(duplicates);
        }
    }

Output:

----- Test 1 -----
Rexon
----- Test 2 -----
Renault
----- Test 3 -----
Renault

You are asking to sort the list and then find the most common item.

I would suggest that the easiest way to sort the list is using the sort method that is built into list.

I would then suggest finding the most common by looping with the for..each construct, keeping track of the current and longest streaks.

I like Yassin Hajaj's answer with streams but I find this way easier to write and easier to read. Your mileage may vary, as this is subjective. :)

import java.util.*;

public class SortingAndMostCommonDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("Renault","BMW","Renault","Renault","Toyota","Rexon","BMW","Opel","Rexon","Rexon"));
        list.sort(Comparator.reverseOrder());
        System.out.println(list);
        System.out.println("The most common is " + mostCommon(list) + ".");
    }

    private static String mostCommon(List<String> list) {
        String mostCommon = null;
        int longestStreak = 0;
        String previous = null;
        int currentStreak = 0;
        
        for (String s : list) {
            currentStreak = 1 + (s.equals(previous) ? currentStreak : 0);
            if (currentStreak > longestStreak) {
                mostCommon = s;
                longestStreak = currentStreak;
            }
            previous = s;
        }
        return mostCommon;
    }
}
Related