Cham - 6 months ago 58

Java Question

Hi I'm having problem with my codes on the Modal value. Here is my code:

`public class basicStatistics {`

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

int n = in.nextInt();

int[] arr = new int[n];

int[] arrCount = new int[n];

int maxCount = 0;

double median = 0.0, mean = 0.0;

for(int i = 0; i < n; i++) {

arr[i] = in.nextInt();

mean = mean + arr[i];

}

mean = mean/n;

for(int i = 0; i < n; i++) {

for(int j = 0; j < n; j++){

if(arr[i] == arr[j]){

arrCount[i]++;

}

if(maxCount < arrCount[i])

maxCount = i;

}

}

Arrays.sort(arr);

if(n%2 == 0) {

median = arr[n/2] + arr[n/2-1];

median = median/2;

} else {

median = arr[n/2];

}

System.out.printf("%.1f\n", mean);

System.out.printf("%.1f\n", median);

System.out.println(arr[maxCount]);

}

}

The issue is I can't get the Modal value right when the input is this: http://pastebin.com/HCqTrimY I used pastebin as it inputs 2500 numbers. My code outputs the array value 259 instead of 2184 for Mode however if the input is n = 10 and the numbers = 64630 11735 14216 99233 14470 4978 73429 38120 51135 67060 I get the mode value correct or for other scenario.

I also wanted to transform the code to a more efficient one utilizing the Java8 structure. Thank you in advanced!

Answer

If you want to use Java 8, you can make that code a lot shorter. First, the `mean`

: Here you can create a `stream`

from your `int`

-array `arr`

and then just call the `average`

method:

```
double mean = IntStream.of(arr).average().getAsDouble();
```

The `median`

is pretty much the same as in your code; I just put it on fewer lines by using a ternary expression (`... ? ... : ...`

) instead of a multi-line `if/else`

:

```
Arrays.sort(arr);
int len = arr.length;
double median = len % 2 == 0 ? (arr[len/2-1] + arr[len/2]) / 2. : arr[len/2];
```

The `mode`

is a bit more difficult, last but not least since you seem to need the smallest mode in case there are multiple numbers appearing most often. While your double-`for`

-loop approach would work, too, it has quadratic complexity, which could become a problem for larger data sets. Instead, you should use a `Map`

to count the different numbers. In Java 8, this can be done very easily using `Collectors.groupingBy`

and `Collectors.counting`

. Then, just determine the `max`

of the counts, `filter`

the numbers that have that count, and get the `min`

of those.

```
Map<Integer, Long> counts = IntStream.of(arr).boxed()
.collect(Collectors.groupingBy(x -> x, Collectors.counting()));
Long max = counts.values().stream().max(Comparator.naturalOrder()).get();
int mode = counts.entrySet().stream()
.filter(e -> e.getValue().equals(max))
.min(Comparator.comparing(Entry::getKey)).get().getKey();
```