Finding Multiple Modes In An Array

16,079

Solution 1

The following code will return you an Integer[] containing the modes. If you need an int[] instead, you still need to convert the Integer instances to ints manually. Probably not the most efficient version, but its matches closely to your code

public static Integer[] mode(int a[]){
  List<Integer> modes = new ArrayList<Integer>(  );
  int maxCount=0;   
  for (int i = 0; i < a.length; ++i){
    int count = 0;
    for (int j = 0; j < a.length; ++j){
      if (a[j] == a[i]) ++count;
    }
    if (count > maxCount){
      maxCount = count;
      modes.clear();
      modes.add( a[i] );
    } else if ( count == maxCount ){
      modes.add( a[i] );
    }
  }
  return modes.toArray( new Integer[modes.size()] );
}

Solution 2

After a long night of programming, I finality got a program that will print out the mode/modes of an array. Or will even tell you if there isn't a mode (say, if no input occurred more than once or all the inputs occurred the same amount of times: ex. 1, 1, 2, 2, 3, 3, 4, 4). Some limitations of the program are that you must enter more than one number, and you cannot enter more than 10000 numbers or a negative number (if you wanted to enter a negative number, you would just have to tweak all the for loops involving the values[][] array. Some cool things about my program are that it prints out how many times each of you inputs occurred along with the mode of your array. And all of the print outs grammar change according to the amount of info (Ex. The mode of your array is 2; The modes of your array are 1 & 2; The modes of your array are 0, 2, 5, & 8). There is also a bubble sort function example in the program for anyone who thought that they needed a sorter function in their mode program. Hope this helps, I included a lot of pseudo code to help anyone who doesn't see how my logic progress throughout the program. (FYI: It is java, and was compiled in BlueJ)

import java.util.Scanner;
public class Mode
{
    public static void main (String args [])
    {
        Scanner scan = new Scanner(System.in);
        int MAX_INPUTS = 10000; boolean flag = false;
        System.out.print ("Input the size of your array: ");
        int size; // How many nubers will be in the user array
        do
        {
            size = scan.nextInt();
            if (size == 1)
            {
                System.out.print ("\nError. You must enter a number more than 1.\n\n"); 
                continue;
            }
            else if (size > MAX_INPUTS || size < 0)
            {
                System.out.print ("\nError. You muste enter a number less than " + MAX_INPUTS + " or greater than 0\n\n");
                continue;
            }
            else
                flag = true; // a ligit answer has been entered.
        }
        while (flag != true);
        int array[] = new int[size], values[][] = new int[2][MAX_INPUTS + 1], ticks = 0;

        System.out.print ("\nNow input the numbers for your array.\n\n");

        /* Taking inputs from the user */        
        while (ticks < size)
        {
            System.out.print ("Number " + (ticks + 1) + ": ");
            array[ticks] = scan.nextInt();
            if (array[ticks] > MAX_INPUTS || array[ticks] < 0)
            {
                System.out.print ("\nError. Number cannot be greater than " + MAX_INPUTS + " or less than 0\n\n");
                continue;
            }               
            ++ticks;
        }

        /* 
         * values[][] array will hold the info for how many times numbers 0 - 10000 appear in array[]. Column 0 will hold numbers from 0 -1000, and column 1 will hold the number of
         * of repititions the number in column 0 occured in the users inputed array.
         */

        for (int i = 0; i < MAX_INPUTS; ++i) // Initalize Column zero with numbers starting at zeor, and ending and MAX_INPUTS.
            values[0][i] = i;

        for (int i = 0; i < size; ++i) // Find the repatitions of the numbers in array[] that correspond to the number in column zere of values[][].
            for (int j = 0; j < MAX_INPUTS; ++j)
                if (array[i] == j)
                    ++values[1][j];

        sort (array, size);
        System.out.print ("\n\nHere are the numbers you entered.\n\n"); // show the values the user entered in ascending order.

        for (int i = 0; i < size; ++i)
        {
            if (i == size - 1) // the last inputed number
                System.out.print (array[i]); // don't allow an extra comma.
            else
                System.out.print (array[i] + ", ");
        }

        // Show the user how many times each of the values he/she entered occured.

        System.out.print ("\n\nThis is the amount of times each of the values you entered occured:\n");

        for (int i = 0; i < MAX_INPUTS; ++i)
        {
            if (values[1][i] == 1)
                System.out.print (i + " was entered " + values[1][i] + " time\n"); // avoid: 2 was entered 1 times
            else if (values[1][i] != 0)
                System.out.print (i + " was entered " + values[1][i] + " times\n"); // avoid: 2 was entered 2 time
        }


        /* -------------------------------------------------------------------- | Finding the Mode/Modes | -------------------------------------------------------------------- */
        /* The process begins with creating a second array that is the exactly the same as the values[][] (First for loop). Then I sort the duplicate[] array to find the mode 
         * (highest number in the duplicate[]/values[][] arrays. Int max is then assigned the highest number. Remembering that the values[][] array: column 0 contains numbers ranging
         * from 1 to 10000, it keeps track of where the numbers in column were originally located, in which you can compare to the duplicate array which is sorted. Then I can set 
         * up a flag that tells you whether there is more than one mode. If so, the printing of these modes will look neater and the grammar can be changed accordingly.
         */

        int duplicate[] = new int [10001], mode[] = new int [size], max, mode_counter = 0;
        boolean multi_mode = false, all_same;

        for (int i = 0; i < MAX_INPUTS; ++i)
            duplicate[i] = values[1][i]; // copy values array.

        sort (duplicate, MAX_INPUTS);
        max = duplicate[MAX_INPUTS - 1]; // the last number in the sorted array is the greatest.
        all_same = test (duplicate, MAX_INPUTS, size, max); // this is the test to see if all the numbers in the user array occured the same amount of times.
        int c = 0; // a counter

        /* The mode of the user inputed array will be recorded in the values array. The sort of the duplicate array told me what was the higest number in that array. Now I can 
         * see where that highest number used to be in the original values array and recored the corresponding number in the column zero, which was only filled with numbers 0 -
         * 10000. Thus telling me the mode/modes.
         */

        for (int i = 0; i < MAX_INPUTS; ++i)
        {
            if (values[1][i] == max)
            {
                mode[c++] = values[0][i];
                ++mode_counter;
            }
        }

        if (mode[1] != 0) //mode[0] (the first cell, has a number stored from the last for loop. If the second cell has a number other than zero, that tells me there is more than 1 mode.
            multi_mode = true;

        if (multi_mode == false)
            System.out.print ("\nThe mode of your array is " + mode[0]); // For correct grammer.
        else if (all_same == true)
            System.out.print ("\nAll of the numbers entered appeared the same amount of times. "); // See the boolean function for more details
        else // If here there is more than one mode.
        {
            System.out.print ("\nThe modes of yoru array are ");
            for (int i = 0; i < mode_counter; ++i)
            {
                if (mode_counter > 2 && i == (mode_counter - 1))  // If there is more than two modes and the final mode is to be printed.
                    System.out.print ("& " + mode[i]);
                else if (mode_counter == 2)
                { // This is true if there is two modes. The else clause will print the first number, and this will print the amper sign and the second mode.
                    System.out.print (mode[0] + " & " + mode[1]); 
                    break;
                }
                else
                    System.out.print (mode[i] + ", ");
            }
        }
    }

    public static void sort (int list[], int max) // Its the bubble sort if you're wondering.
    {
        int place, count, temp;        
        for (place = 0; place < max; ++place)
            for (count = max - 1; count > place; --count)
                if (list[count - 1] > list[count])
                {
                        temp = list[count-1];
                        list[count - 1] = list[count];
                        list[count] = temp;
                }
    }

    /* The test to see if there isn't a mode. If the amount of the mode number is the same as the amount of numbers there are in the array is true, or if the size entered by the 
     * user (input) modulo the mode value is equal to zero (say, all the numbers in an array of ten were entered twice: 1, 1, 2, 2, 3, 3, 4, 4, 5, 5). */
    public static boolean test (int list[], int limit, int input, int max)
    {
        int counter = 0, anti_counter = 0;
        for (int i = 0; i < limit; ++i)
            if (list[i] == max)
                ++counter; // count the potential modes
            else if (list[i] !=0 && list[i] != max)
                ++anti_counter; // count every thing else except zeros.


        if (counter == input || (input % max == 0 && anti_counter == 0) )
            return true;
        else
            return false;
    }
}
Share:
16,079
Daniel Cook
Author by

Daniel Cook

Updated on August 03, 2022

Comments

  • Daniel Cook
    Daniel Cook almost 2 years

    I'm trying to write a java method which finds all the modes in an array. I know there is a simple method to find the mode in an array but when there are more than one single mode my method outputs only one of them. I've tried to find a way but am nit sure how to approach this problem. Can anyone help me out to find all the modes in the array? Thanks.

    Yes here is my code which outputs only one mode even if multiple modes exist.

    public static int mode(int a[]){
      int maxValue=0, maxCount=0;   
      for (int i = 0; i < a.length; ++i){
        int count = 0;
        for (int j = 0; j < a.length; ++j){
          if (a[j] == a[i]) ++count;
        }
        if (count > maxCount){
          maxCount = count;
          maxValue = a[i];
        }
      }
      return maxValue;
    }
    

    okay here's an example: 30 30 30 34 34 23

    In this set of numbers there is only one mode, which is 30.

    30 30 30 34 34 34 23

    But in this set there are two modes, 30 and 34. I want my code to be able to output both of them, whereas it only prints one. It prints only 30.

  • Robin
    Robin over 12 years
    Say what ... this won't make any difference
  • Daniel Cook
    Daniel Cook over 12 years
    you're right, that just does the same thing as my previous code.
  • James Corr
    James Corr over 12 years
    Updated my solution. This will work now. Not sure if you were just wanting to print them or have them returned. This solution prints them.
  • Daniel Cook
    Daniel Cook over 12 years
    uh this solution is printing the modes the number of times it occurs, whereas I want it to be printed only once. Thanks though now I have a general idea how this code works.
  • Brian Roach
    Brian Roach over 12 years
    Yeah, you're pretty much locked into O(n^2). The only optimization I can think of is if you were to use maxCount to limit the inner loop; if ((j.length - (j + 1)) + count) < maxCount you can bail.