Finding the most frequent value in an array and then choosing the lowest value if there is a tie

Viewed 297

I have the following program which looks up an array "a" and then output the value in the array which appears the most frequently. However one other condition that I would like to implement is that in the case of a tie where two different values appear an equal amount of times, the lowest value gets output.

So for the following code with an array:

int a[] = {34, 34, 20, 20, 15};

It outputs 34 however I want it to output 20 instead, since that is a lower value and appears just as many times in the array.

public class Arrays3 {
    public static void main(String[] args){
        int a[] = {34, 34, 20, 20, 15};
        mode(a);
    }
    public static int mode(int[] a) {
        int[] counts = new int[101];
        int maxCount = 0;
        int maxKey = 0;

        for(int i = 0; i < a.length; i++) {
            counts[a[i]]++;
            if(counts[a[i]] > maxCount) {
                maxCount = counts[a[i]];
                maxKey = a[i];
            }
        }
        System.out.println(maxKey);
        return maxKey;
    }
}
3 Answers

You could check against maxKey and then do something along the lines of:

 if(counts[a[i]] == maxCount && counts[a[i]] < maxKey) {
       maxKey = counts[a[i]];
 }

So that if there is ever a tie, the maxKey will be set to the smaller element. Then if count[a[i]] is ever greater than maxCount, maxKey will be overridden and become the element that occurs most often:

for(int i = 0; i < a.length; i++) {
     counts[a[i]]++;

     if(counts[a[i]] > maxCount) {
          maxCount = counts[a[i]];
          maxKey = a[i];
      }
      if(counts[a[i]] == maxCount && counts[a[i]] < maxKey) {
        maxKey = a[i];
      }
}
System.out.println(a[maxKey]);

Output

20

An interesting solution (that I had fun writing) would be to first create a frequency Map by streaming your array and using Collectors.groupingBy with Collectors.counting().

Then, we could stream that and use Collectors.groupingBy again to create a Map<Long, SortedSet<Integer>> (the key would be the frequency and the value would be the sorted set of values in your array with that frequency).

Finally, we can sort the Map so that the highest frequency comes first, and simply grab the lowest element from the SortedSet:

int[] a = {34, 34, 20, 20, 15};

var lowest = Arrays.stream(a)
                   .boxed()
                   .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                   .entrySet()
                   .stream()
                   .collect(Collectors.groupingBy(Map.Entry::getValue,
                           Collectors.mapping(Map.Entry::getKey, Collectors.toCollection(TreeSet::new))))
                   .entrySet()
                   .stream()
                   .sorted(Comparator.comparing(Map.Entry::getKey, Comparator.reverseOrder()))
                   .map(Map.Entry::getValue)
                   .mapToInt(TreeSet::first)
                   .findFirst();

lowest.ifPresent(System.out::println);

Output:

20
  • You want to seek for the minimum value, so I suggest put int maxKey = Integer.MAX_VALUE;
  • Then each time a better counts is found, we must compare to update the maxKey After all, the solution will look like this

    int[] counts = new int[101];
    int maxCount = 0;
    int maxKey = Integer.MAX_VALUE;
    
    for(int i = 0; i < a.length; i++) {
        counts[a[i]]++;
        if(counts[a[i]] >= maxCount) {
            maxCount = counts[a[i]];
            if(a[i] < maxKey) maxKey = a[i];
    
        }
    }
    System.out.println(maxKey);
    return maxKey;
    

Have fun coding

Related