0

As the title states, I need to find the mode of an array. However, there are a few stipulations to this:

1) If no mode exists (i.e. each element appears only once, or equal times) return Double.NaN

2) If more than one mode exists (i.e. {1,2,2,3,4,5,5,6} would give two modes, 2 and 5) return Double.NaN

Basically, it should only return an element of the array if it is definitely the mode of the array, and appears at least once more than all other elements. Any other time, it should return Double.NaN

My current code returns a mode. However, if two numbers appear equally, it returns the latter of the two as the mode, not NaN. Also, doesn't return NaN if no mode exists.

Any help is appreciated.

Here is what I have so far:

public double mode(){
    double[] holder = new double[data.length];
    double tempMax = 0, permMax = 0, location = 0, arrayMode = 0; 
    for (int i = 0; i < data.length; ++i) {
        int count = 0;
        for (int j = 0; j < data.length; ++j) {
            if (data[j] == data[i])
                ++count;
        }
        holder[i] = count;
    }

    for (int w = 0; w < holder.length; w++){
    if (holder[w] > tempMax){
        tempMax = holder[w];
        arrayMode = data[w];
    }
    }
    permMax = arrayMode;

    return permMax;
}
Kewl
  • 3,327
  • 5
  • 26
  • 45

2 Answers2

0

The best way to do it is to sort your array, then go through it from start to finish counting the number of instances of each number against the max found so far. If you really need to keep the original order of your numbers, first duplicate the array

public static double mode (double[] data) {
  double maxnum = Double.NaN;
  double num = 0;
  int maxcount = 0;
  int count = 0;
  double[] used = Arrays.copyOf(data, data.length);
  Arrays.sort(data);
  for (int i = 0; i < used.length; i++) {
    if (used[i] == num) {
      count++;
    }
    else {
      num = used[i];
      count = 1;
    }
    if (count == maxCount) {
      maxnum = Double.NaN;
    }
    if (count > maxCount) {
      maxnum = num;
      maxcount = count;
    }
  }
  return maxnum;
}
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • So you say sort it, find the frequency of each element, then compare the frequencies with the previous max frequency. If it is greater than previous, it becomes max. if it equals, return NaN, and if less, max remains unchanged? – slowdawg84 Apr 14 '17 at 15:02
  • @slowdawg84 fundamentally, yes – ControlAltDel Apr 14 '17 at 15:08
0

It is fairly easy to find a duplicate for this question, e.g. here.

That being said, I'd like to add another solution:

public double findMode(int[] inArray) {
        List<Integer> il = IntStream.of(inArray).boxed().collect(Collectors.toList());
        int maxFreq = 0;
        double value = 0;
        for (Integer i : ia){
            if (Collections.frequency(il, i) > maxFreq && i != value){
                maxFreq = Collections.frequency(il, i);
                value = i;
            } else if (Collections.frequency(il, i) == maxFreq && i != value) {
                value = Double.NaN; 
            }
        }
        return value;
}

It turns the int[] into a List<Integer> and uses the Collections.frequency method to get the number of occurrences of each value.

Disclaimer: there are likely some optimizations that I missed.

Community
  • 1
  • 1
Robin Topper
  • 2,295
  • 1
  • 17
  • 25
  • Do you recommend I go with what the linked code says, but change count=0 to count =1? Or implement what you listed here into my existing method? – slowdawg84 Apr 14 '17 at 15:00
  • I modified the last if-else branch in the code you linked to return Double.NaN instead of choose the lower of the two. Thanks for the help everyone! – slowdawg84 Apr 14 '17 at 15:12