2

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.

Daniel Cook
  • 1,856
  • 8
  • 23
  • 28
  • 3
    What do you mean with mode ? What is that simple method to find the mode in an array you are referring to. Any code of your method which only outputs one of them ? – Robin Jan 13 '12 at 22:50
  • yes here is my code which outputs only one mode, even if more than one 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; } – Daniel Cook Jan 13 '12 at 22:59
  • 1
    @Daniel, don't put code in comments; just edit your question. – Kirk Woll Jan 13 '12 at 23:01
  • yeah sorry I altered it. – Daniel Cook Jan 13 '12 at 23:03
  • And what is the relation between that piece of code and your question ? That code just returns the `int` which occurs the most times in the array, while you want to 'find multiple modes' in an array. Do you mean you want to return an array without duplicates ? That is explained [here](http://stackoverflow.com/questions/3028330/remove-duplicates-from-object-array-data-java). If you mean something else, please refine your question – Robin Jan 13 '12 at 23:13
  • 2
    @Robin - that's what the `mode` is - the item in the array ("set" in mathematical terminology) that occurs the most often. In the case of a tie where 2 items are appearing the same number of times the array is `bimodal` and if there's more than 2 items appearing that same number of times, `multimodal` – Brian Roach Jan 13 '12 at 23:15
  • @BrianRoach thanks a lot, now I finally understand the question – Robin Jan 13 '12 at 23:18
  • yeah, I have an array with more than one modes, and want to be able to print all of them. – Daniel Cook Jan 13 '12 at 23:21

5 Answers5

2

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()] );
}
Robin
  • 36,233
  • 5
  • 47
  • 99
  • 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. – Brian Roach Jan 14 '12 at 01:18
1

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;
    }
}
0

Hope this helps. This is my answer. Hope it helps

public List mode(double[] m) {
    HashMap<Double, Double> freqs = new HashMap<Double, Double>();
    for (double d : m) {
        Double freq = freqs.get(d);
        freqs.put(d, (freq == null ? 1 : freq + 1));
    }
    List<Double> mode = new ArrayList<Double>();
    List<Double> frequency = new ArrayList<Double>();
    List<Double> values = new ArrayList<Double>();

    for (Map.Entry<Double, Double> entry : freqs.entrySet()) {
        frequency.add(entry.getValue());
        values.add(entry.getKey());
    }
    double max = Collections.max(frequency);

    for(int i=0; i< frequency.size();i++)
    {
        double val =frequency.get(i);
        if(max == val )
        {
            mode.add(values.get(i));
        }
    }
    return mode;
}
Pukka
  • 11
  • 3
0

Handling multiple mode values: Here initially I am taking a map to get the frequencies of each element. After finding the max repeating value I am storing its map value. While iterating to the map I am checking if this value is repeating for some key and is not 1, if it is then I am adding that key as well. This will get me the multiple modes

public static void mode(int a[]){

    int count=0;
    Map<Integer,Integer> map=new HashMap<>();
    for(int i=0;i<a.length;i++)
    {
        map.put(a[i],map.getOrDefault(a[i],0)+1);
    }
    Set<Integer> set=new HashSet<>();
    int maxValue=0;
    for(int i=0;i<a.length;i++)
    {
        int ct=0;
        for(int j=0;j<a.length;j++)
        {
            if(a[i]==a[j])
                ct++;
        }
        if(ct>count)
        {
            count=ct;
            maxValue=a[i];
        }
        
    }
    set.add(maxValue);
    int k=map.get(maxValue);
    if(k!=1)
    {
    for(Map.Entry m:map.entrySet())
    {
        if((int)m.getValue()==k)
            set.add((int)m.getKey());
    }
    }
    System.out.println("Mode: "+set);
    
}
LW001
  • 2,452
  • 6
  • 27
  • 36
0

Even though this probably isn't the most efficient solution, it will print all the highest modes:

public static int mode(int a[]) {
    int maxValue=-1, 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];
        }
    }

    //loop again and print only the highest modes
    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) {
            System.out.println(a[i]);
        }
    }
}
James Corr
  • 81
  • 8