How to calculate a unique "mode" from an array? - java

I was tasked to find the mode of a given array (unspecified length). The mode is defined as the number that occurs the most uniquely. So, for example, the mode of an array [1.0, 2.0, 3.0, 2.0] is 2.0. However, if there is not a unique number of that value, for example, [1.0, 2.0, 2.0, 3.0, 3.0], the program returns "no mode" or "Double.NaN" in my program.
I have written code that works for 3/4 test cases, but always messes up on catching the case where there are two modes that are the same.
public double mode() {
double modeOne = data[0];
double modeTwo = 0;
int count = 0;
int countOne = 0;
int countTwo = 0;
if(data.length == 1) { // special case: if array length is 1 the mode will always just be that value
modeOne = data[0];
return modeOne;
} // end if
for(int i = 0; i < data.length; i++) { // pulling out first value
double value = data[i];
for(int n = 0; n < data.length; n++) { // comparing first value to all other values
if (data[n] == value) {
count ++; // adding onto a count of how many of the same number there are
}
}
if(modeOne == value || modeTwo == value) { // move on if the modes already have that value
continue;
}
if(count > countOne) { // setting the max count
countTwo = countOne;
countOne = count;
modeTwo = modeOne;
modeOne = value;
}
else if(count > countTwo) { // setting second highest count
countTwo = count;
modeTwo = value;
}
} // end for
if(countOne == 1) { // if all the modes are just one
return Double.NaN;
}
if(countOne == countTwo) { // if there are two of the same modes
return Double.NaN;
}
else {
return modeOne;
}
} //end MODE
For this test case:
double[] data = {1,2,2,3,3,4};
Stat stat1 = new Stat(data);
System.out.println("stat1 mode = " + stat1.mode());
I expect "NaN" but it returns 4. However, it works for the case below:
double[] data = {-5.3, 2.5, 88.9, 0, 0.0, 28, 16.5, 88.9, 109.5, -90, 88.9};
Stat stat1 = new Stat(data);
System.out.println("stat1 mode = " + stat1.mode());
The expected output is 88.9, which the program does correctly output.

Here is an approaching using Streaming API. However, I took the definition of modes which is a set rather than a single number.
import org.junit.Test;
import java.util.Arrays;
import java.util.Map;
import java.util.OptionalLong;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class ModeTest {
private <T extends Number> Set<T> modes(T... input) {
return modes(Arrays.stream(input));
}
/**
* Calculate the modes of a numeric stream. The modes are the values that occurs most often. If no number in the
* stream is repeated, then all the numbers in the stream are modes.
*
* #param input stream of numbers
* #param <T> number type
* #return modes.
*/
private <T extends Number> Set<T> modes(Stream<T> input) {
// transform the input to a map containing the counted entries
final Set<Map.Entry<T, Long>> countedEntries = input
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet();
// Figure out the max value
final OptionalLong max = countedEntries
.parallelStream()
.mapToLong(Map.Entry::getValue)
.max();
// Handle the case where the stream was empty
if (max.isEmpty()) {
return Set.of();
}
return countedEntries
.parallelStream()
.filter(e -> e.getValue() == max.getAsLong())
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
#Test
public void oneMode() {
final Double[] input = new Double[]{1.0, 1.1, 1.2, 2.0, 2.0, 3.0};
assertEquals(modes(input), Set.of(2.0));
}
#Test
public void multipleModes() {
final Stream<Double> input = Stream.of(1.0, 1.1, 1.2, 2.0, 2.0, 3.0, 3.0);
assertEquals(modes(input), Set.of(2.0, 3.0));
}
#Test
public void allSingles() {
final Stream<Double> input = Stream.of(1.0, 1.1, 1.2, 2.0, 3.0);
assertEquals(modes(input), Set.of(1.0, 1.1, 1.2, 2.0, 3.0));
}
#Test
public void largeRandomSet() {
Integer[] randoms = new Integer[204800];
for (int i = randoms.length - 1; i >= 0; --i) {
randoms[i] = ThreadLocalRandom.current().nextInt(200);
}
assertFalse(modes(randoms).isEmpty());
}
#Test
public void emptyStream() {
final Stream<Double> input = Stream.of();
assertEquals(modes(input), Set.of());
}
}

There you go no Collection etc... pure hard programming :)
public double mode(double[] data)
{
if(data.length==1)
return data[0];
double temp;
double [] fr = new double [data.length]; //store frequency
int visited = -1;
for(int i = 0; i < data.length; i++)
{
int count = 1;
for(int j = i+1; j < data.length; j++)
{
if(data[i] == data[j])
{
count++;
fr[j] = visited;
}
}
if(fr[i] != visited)
fr[i] = count;
}
for (int i = 0; i < fr.length; i++) // sort array in decreasing order
{
for (int j = i + 1; j < fr.length; j++)
{
if (fr[i] < fr[j])
{
temp = data[i];
data[i] = data[j];
data[j] = temp;
temp = fr[i];
fr[i] = fr[j];
fr[j] = temp;
}
}
}
if(fr[0] == fr[1])
return Double.NaN;
else
return data[0];
}

Since I was in the mood for a small challenge, I did write my own solution using a Map to count the individual values.
Then you retrieve the highest count available and iterate over the map again to determine if multiple entries have the same highest count, if so, you'll return NaN.
public static double calculateMode(double[] numbers) {
Map<Double, Integer> lookupMap = new TreeMap<>();
for (double number : numbers) {
if (lookupMap.get(number) != null) {
lookupMap.put(number, lookupMap.get(number) + 1);
} else {
lookupMap.put(number, 1);
}
}
int max = -1;
double maxKey = Double.NaN;
for (Entry<Double, Integer> entry : lookupMap.entrySet()) {
if (entry.getValue() > max) {
max = entry.getValue();
maxKey = entry.getKey();
}
}
int foundMax = 0;
for (Entry<Double, Integer> entry : lookupMap.entrySet()) {
if (entry.getValue() == max) {
foundMax++;
}
}
if (foundMax > 1) {
return Double.NaN;
}
return maxKey;
}
Method call:
public static void main(String[] args) {
double[] data = {1, 2, 2, 3, 3, 4};
double[] data2 = {-5.3, 2.5, 88.9, 0, 0.0, 28, 16.5, 88.9, 109.5, -90, 88.9};
System.out.println("Expected NaN - and was: " + calculateMode(data));
System.out.println("Expected 88.90 - and was: " + calculateMode(data2));
}
Outputs:
Expected NaN - and was: NaN
Expected 88.90 - and was: 88.9

So I felt challenged as well and got a solution without the use of Collections.
Not a really nice solution but it seems to work:
public class TestMode
{
private static class NumberFrequency
{
double number;
int frequency;
}
public static double calculateMode(double[] numbers)
{
// Maybe array empty
if ((numbers == null) || (numbers.length == 0))
return Double.NaN;
// Initialize array with frequencies
NumberFrequency[] array;
int size = 0;
array = new NumberFrequency[numbers.length];
// Loop over numbers determining frequencies
for (double number : numbers)
{
// Maybe encountered before
int index;
for (index = 0; index < size; index++)
{
if (array[index].number == number)
break;
}
// Update array
NumberFrequency elm;
if (index == size)
{
elm = new NumberFrequency();
elm.number = number;
elm.frequency = 0;
array[index] = elm;
size++;
}
else
elm = array[index];
elm.frequency += 1;
} // for all numbers
// Initialize element with highest frequency
int index_highest;
int highest_freq;
int nr_occurs;
index_highest = 0;
highest_freq = array[0].frequency;
nr_occurs = 1;
// Search 'better' element
int counter;
for (counter = 1; counter < size; counter++)
{
if (array[counter].frequency > highest_freq)
{
index_highest = counter;
highest_freq = array[counter].frequency;
nr_occurs = 1;
}
else if (array[counter].frequency == highest_freq)
nr_occurs++;
}
// Return result
if (nr_occurs == 1)
return array[index_highest].number;
else
return Double.NaN;
} // calculateMode
public static void main(String[] args)
{
double[] data = {1, 2, 2, 3, 3, 4};
double[] data2 = {-5.3, 2.5, 88.9, 0, 0.0, 28, 16.5, 88.9, 109.5, -90, 88.9};
System.out.println("Expected NaN - and was: " + calculateMode(data));
System.out.println("Expected 88.90 - and was: " + calculateMode(data2)); }
} // class TestMode

To add one more alternative and because I also felt challenged as well:
The general idea is to generate a frequency array, fore the given example above
[1.0, 2.0, 2.0, 3.0, 3.0]
[1, 2, 2, 2, 2]
which indicates how many times the element at the same index is in the input, then find the max value in the frequency array, and finally check if all values with the same frequency are equal.
public static double mode(double [] data) {
if(data == null || data.length < 1){
return Double.NaN;
}
int [] freq = new int [data.length];
for(int i = 0; i<data.length; i++){
for(int j = 0; j<data.length; j++){
if(data[i]==data[j]){
freq[i]++;
}
}
}
int max = 0;
double mode = data[0];
for(int i = 0; i<freq.length; i++){
if(freq[i]>max){
max = freq[i];
mode = data[i];
}
}
for(int i = 0; i<freq.length; i++){
if(freq[i] == max){
if(mode != data[i]){
return Double.NaN;
}
}
}
return mode;
}

Related

If statement returns index of only the first value meeting condition? Java

I have been tasked with writing a class with a non-empty array 'temperatures' which stores the temperatures of 365 days of a year.
My task is to write a method returning the day of the year with the lowest temperature.
For example, if the array temperatures = {0,0,-10,-10,0,......,0}. The corresponding result should be 3, despite there being two equal values with the lowest temperature of the set, as the 3rd day (second index) was the first to have the lowest value.
I have correctly written out the code, however, I'm unsure as to why, in my second If statement, it returns only the day with the lowest value and not all the days with the lowest value.
Here's my code
public static int coldest(double[] temperatures) {
double minimum = temperatures[0];
for (double temp : temperatures) {
if (temp < minimum) {
minimum = temp;
}
}
for (int i = 0; i < temperatures.length; i++) {
if (Math.abs(minimum - temperatures[i]) < 0.000000001) {
return i + 1;
}
}
return -1;
}
For example, if I define double[] a = {-5,2,-5,2,-5,......2};, surely within the second For Loop, it will return 1,3,5,7... as all those days satisfy the If criteria, rather than just 1.
I apologise if I haven't written my question very clear, this is my first time asking here.
My task is to write a method returning the day of the year with the
lowest temperature.
If it is the case, your logic is flawed e.g. the following condition doesn't make any sense:
if (Math.abs(minimum - temperatures[i]) < 0.000000001)
Do it as follows:
public class Main {
public static void main(String args[]) {
System.out.println(coldest(new double[] { 0, 0, -10, -10, 0, 0 }));
}
public static int coldest(double[] temperatures) {
if (temperatures == null || temperatures.length == 0) {
return -1;
}
double minimum = temperatures[0];
for (double temp : temperatures) {
if (temp < minimum) {
minimum = temp;
}
}
for (int i = 0; i < temperatures.length; i++) {
if (minimum == temperatures[i]) {
return i + 1;
}
}
return -1;
}
}
Output:
3
If your requirement is to get the list of all days with the minimum temperature, you need to return an array instead of a single value e.g.
import java.util.Arrays;
public class Main {
public static void main(String args[]) {
// Test
System.out.println(Arrays.toString(coldestDays(new double[] { 0, 0, -10, -10, 0, 0 })));
}
public static int[] coldestDays(double[] temperatures) {
if (temperatures == null || temperatures.length == 0) {
return new int[0];
}
double minimum = temperatures[0];
int count = 0;// To store the required size of the array
for (double temp : temperatures) {
if (temp < minimum) {
minimum = temp;
}
}
for (double t : temperatures) {
if (t == minimum) {
count++;
}
}
int[] minTemps = new int[count];// Create the array
int index = 0;
for (int i = 0; i < temperatures.length; i++) {
if (minimum == temperatures[i]) {
minTemps[index++] = i + 1;// Store the (index +1 ) of the minimum temperatures
}
}
return minTemps;
}
}
Output:
[3, 4]
I am not sure if you have reached to the level of using Java collections. If yes, you can use an ArrayList and in that case, you won't need to find the count of days with the minimum temperatures first in order to create an array of appropriate size.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String args[]) {
// Test
System.out.println(coldestDays(new double[] { 0, 0, -10, -10, 0, 0 }));
}
public static List<Integer> coldestDays(double[] temperatures) {
if (temperatures == null || temperatures.length == 0) {
return new ArrayList<Integer>();
}
double minimum = temperatures[0];
List<Integer> days = new ArrayList<Integer>();
for (double temp : temperatures) {
if (temp < minimum) {
minimum = temp;
}
}
for (int i = 0; i < temperatures.length; i++) {
if (minimum == temperatures[i]) {
days.add(i + 1);// Store the (index +1 )of the minimum temperatures
}
}
return days;
}
}
Output:
[3, 4]
I think you might be confused about what the `return' statement actually does.
Its primary action is 'exit from this function', or more specifically, 'exit from the current invocation of this function'. From that, it should be clear enough that you can only do that once. Once you've exited, you've exited.
Its secondary action is to provide the value of the function invocation, i.e., what value is to be 'returned' to the caller. The function is declared to return some 'int' value (int coldest(...)) and the return statement provides that (single) int value.
Reason is return in second if statement breaks your for loop. I am suggesting you to this kind of solution. Instead of returning one int value, You can return list of Integer values:
public static List<Integer> coldest(double[] temperatures) {
double minimum = temperatures[0];
List<Integer> arrayList = new ArrayList<>();
for (double temp : temperatures) {
if (temp < minimum) {
minimum = temp;
}
}
for (int i = 0; i < temperatures.length; i++) {
if (Math.abs(minimum - temperatures[i]) < 0.000000001) {
arrayList.add((i + 1));
}
}
return arrayList;
}

HashMap sum algorithm

This is my first attempt to use HashMap. Given is a table with n integers. Goal is to calculate in how many common subtables the sum of the numbers is x. I've been trying trying the following. Sample output is 2,10,4. I'm getting 2,10,2. Any idea where I go wrong? Thanks in advance.
public class FindSum {
long count(int[] t, int x) {
HashMap<Integer, Integer> totals = new HashMap<>();
long count = 0;
int sum = 0;
for (int i = 0; i < t.length; i++) {
int value = t[i];
sum += value;
if (totals.containsKey(sum - x)) {
count += totals.get(sum - x);
}
if (value == x) {
count++;
}
totals.put(sum, totals.getOrDefault(sum, 0) + 1);
}
return count;
}
}
Sample output:
FindSum f = new FindSum();
System.out.println(s.count(new int[] {1,3,2,4}, 4)); // 2
System.out.println(s.count(new int[] {0,0,0,0}, 0)); // 10
System.out.println(s.count(new int[] {1,-1,1,-1}, 0)); // 4

finding two pairs from integer array out of two elements

Two pairs: If there are two pairs of dice with the same number, the player scores the sum of these dice. If not, the player scores 0. For example, 1, 1, 2, 3, 3 placed on "two pairs" gives 8.
examples:
1,1,2,3,3 results 8
1,1,2,3,4 results 0
1,1,2,2,2 results 6
How can find this efficiently?
I've been using following code to find a single pair
int max_difference = 0;
int val1 = 0 , val2 = 0;
Arrays.sort(dice);
for (int i = 0; i < dice.length - 1; i++) {
int x = dice[i+1] - dice[i];
if(x <= max_difference) {
max_difference = x;
val1 = dice[i];
val2 = dice[i+1];
}
}
pairScore = val1 + val2;
No need to make it that complicated, since you're only searching for the resulting number...
int prev = 0;
int result = 0;
int pairs = 0;
Arrays.sort(dice);
for (int i = 0; i < dice.length; i++)
{
int current = dice[i];
if (current == prev)
{
result += current*2;
pairs++;
prev = 0;
}
else prev = current;
}
if (pairs == 2) return result;
else return 0;
I'd use a frequency map, i.e. the number is the key and the value is a counter (so a Map<Integer, Integer>). However, since it is used for dices you could simplify that using an array with a length equal to the maximum dice value (6 for standard dice). Then check the frequencies for each number and get the number of pairs from it.
Example:
int[] diceFrequency = new int[6];
//assuming d is in the range [1,6]
for( int d : dice ) {
//increment the counter for the dice value
diceFrequency[d-1]++;
}
int numberOfPairs = 0;
int pairSum = 0;
for( int i = 0; i < diceFrequency.length; i++ ) {
//due to integer division you get only the number of pairs,
//i.e. if you have 3x 1 you get 1 pair, for 5x 1 you get 2 pairs
int num = diceFrequency[i] / 2;
//total the number of pairs is just increases
numberOfPairs += num;
//the total value of those pairs is the dice value (i+1)
//multiplied by the number of pairs and 2 (since it's a pair)
pairSum += (i + 1 ) * 2 * num;
}
if( numerOfPairs >= 2 ) {
//you have at least 2 pairs, do whatever is appropriate
}
How about use hashmap as below?
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 1, 2, 3, 3, 4);
Map<Integer, Integer> map = Maps.newHashMap();
int result = 0;
for (int i : list) {
int frequency = (int) MapUtils.getObject(map, i, 0);
if (frequency < 2) {
map.put(i, ++frequency);
}
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() > 1) {
result += entry.getKey() * entry.getValue();
}
}
System.out.println(result);
}
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 1, 2, 3, 3);
Map<Integer, Integer> map = new HashMap<>();
int count= 0;
for (int num : list)
if(map.containsKey(num ))
map.put(num , map.get(num )+1);
else
map.put(num , 1);
for (int num : map.keySet()) {
if (map.get(num ) > 1) {
count= count+ (num * map.get(num ));
}
}
System.out.println(count);
}
I hope, I could understand the problem. So we can use thiscode part.
List<Integer> diceList = new ArrayList<Integer>();
diceList.add(1);
diceList.add(1);
diceList.add(2);
diceList.add(4);
diceList.add(3);
diceList.add(3);
diceList.add(6);
diceList.add(8);
Integer prev = null, score = 0;
boolean flag = false;
for (Integer val : diceList) {
if (prev == null || !prev.equals(val)) {
if (flag) {
score = score + prev;
flag = false;
}
prev = val;
} else if (prev == val) {
score = score + prev;
flag = true;
}
}
System.out.println(score);

Arrays, Statistics, and calculating mean, median, mode, average and sqrt

I need to implement four static methods in a class named ArrayStatistics. Each of the four methods will calculate the mean, median, mode, and population standard deviation, respectively, of the values in the array.
This is my first time working with Java, and cannot figure out what should I do next. I was given some test values for, you guessed it, test out my program.
public class ArrayStatistics {
public static void main(String[] args) {
final int[] arr;
int[] testValues = new int[] { 10, 20, 30, 40 };
meanValue = a;
meadianValue = b;
modeValue = c;
sqrtDevValue = d;
average = (sum / count);
System.out.println("Average is " );
}
static double[] mean(int[] data) {
for(int x = 1; x <=counter; x++) {
input = NumScanner.nextInt();
sum = sum + inputNum;
System.out.println();
}
return a;
}
static double[] median(int[] data) {
// ...
}
public double getMedian(double[] numberList) {
int factor = numberList.length - 1;
double[] first = new double[(double) factor / 2];
double[] last = new double[first.length];
double[] middleNumbers = new double[1];
for (int i = 0; i < first.length; i++) {
first[i] = numbersList[i];
}
for (int i = numberList.length; i > last.length; i--) {
last[i] = numbersList[i];
}
for (int i = 0; i <= numberList.length; i++) {
if (numberList[i] != first[i] || numberList[i] != last[i]) middleNumbers[i] = numberList[i];
}
if (numberList.length % 2 == 0) {
double total = middleNumbers[0] + middleNumbers[1];
return total / 2;
} else {
return b;
}
}
static double[] mode(int[] data) {
public double getMode(double[] numberList) {
HashMap<Double,Double> freqs = new HashMap<Double,Double>();
for (double d: numberList) {
Double freq = freqs.get(d);
freqs.put(d, (freq == null ? 1 : freq + 1));
}
double mode = 0;
double maxFreq = 0;
for (Map.Entry<Double,Doubler> entry : freqs.entrySet()) {
double freq = entry.getValue();
if (freq > maxFreq) {
maxFreq = freq;
mode = entry.getKey();
}
}
return c;
}
static double[] sqrt(int[] sqrtDev) {
return d;
}
}
This is pretty easy.
public double mean(ArrayList list) {
double ans=0;
for(int i=0; i<list.size(); i++) {
ans+=list.get(i); }
return ans/list.size()
}
`
Median:
public void median(ArrayList list) {
if(list.size()%==2) return (list.get(list.size()/2)+list.get(list.size()+1))/2;
else return list.get((list.size()/2)+1)
}
For Mode, just a keep a tally on the frequency of each number occurrence, extremely easy.
For standard deviation find the mean and just use the formula given here: https://www.mathsisfun.com/data/standard-deviation-formulas.html

How to calculate mean, median, mode and range from a set of numbers

Are there any functions (as part of a math library) which will calculate mean, median, mode and range from a set of numbers.
Yes, there does seem to be 3rd libraries (none in Java Math). Two that have come up are:
http://opsresearch.com/app/
http://www.iro.umontreal.ca/~simardr/ssj/indexe.html
but, it is actually not that difficult to write your own methods to calculate mean, median, mode and range.
MEAN
public static double mean(double[] m) {
double sum = 0;
for (int i = 0; i < m.length; i++) {
sum += m[i];
}
return sum / m.length;
}
MEDIAN
// the array double[] m MUST BE SORTED
public static double median(double[] m) {
int middle = m.length/2;
if (m.length%2 == 1) {
return m[middle];
} else {
return (m[middle-1] + m[middle]) / 2.0;
}
}
MODE
public static int mode(int a[]) {
int maxValue, maxCount;
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;
}
UPDATE
As has been pointed out by Neelesh Salpe, the above does not cater for multi-modal collections. We can fix this quite easily:
public static List<Integer> mode(final int[] numbers) {
final List<Integer> modes = new ArrayList<Integer>();
final Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();
int max = -1;
for (final int n : numbers) {
int count = 0;
if (countMap.containsKey(n)) {
count = countMap.get(n) + 1;
} else {
count = 1;
}
countMap.put(n, count);
if (count > max) {
max = count;
}
}
for (final Map.Entry<Integer, Integer> tuple : countMap.entrySet()) {
if (tuple.getValue() == max) {
modes.add(tuple.getKey());
}
}
return modes;
}
ADDITION
If you are using Java 8 or higher, you can also determine the modes like this:
public static List<Integer> getModes(final List<Integer> numbers) {
final Map<Integer, Long> countFrequencies = numbers.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
final long maxFrequency = countFrequencies.values().stream()
.mapToLong(count -> count)
.max().orElse(-1);
return countFrequencies.entrySet().stream()
.filter(tuple -> tuple.getValue() == maxFrequency)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
Check out commons math from apache. There is quite a lot there.
public static Set<Double> getMode(double[] data) {
if (data.length == 0) {
return new TreeSet<>();
}
TreeMap<Double, Integer> map = new TreeMap<>(); //Map Keys are array values and Map Values are how many times each key appears in the array
for (int index = 0; index != data.length; ++index) {
double value = data[index];
if (!map.containsKey(value)) {
map.put(value, 1); //first time, put one
}
else {
map.put(value, map.get(value) + 1); //seen it again increment count
}
}
Set<Double> modes = new TreeSet<>(); //result set of modes, min to max sorted
int maxCount = 1;
Iterator<Integer> modeApperance = map.values().iterator();
while (modeApperance.hasNext()) {
maxCount = Math.max(maxCount, modeApperance.next()); //go through all the value counts
}
for (double key : map.keySet()) {
if (map.get(key) == maxCount) { //if this key's value is max
modes.add(key); //get it
}
}
return modes;
}
//std dev function for good measure
public static double getStandardDeviation(double[] data) {
final double mean = getMean(data);
double sum = 0;
for (int index = 0; index != data.length; ++index) {
sum += Math.pow(Math.abs(mean - data[index]), 2);
}
return Math.sqrt(sum / data.length);
}
public static double getMean(double[] data) {
if (data.length == 0) {
return 0;
}
double sum = 0.0;
for (int index = 0; index != data.length; ++index) {
sum += data[index];
}
return sum / data.length;
}
//by creating a copy array and sorting it, this function can take any data.
public static double getMedian(double[] data) {
double[] copy = Arrays.copyOf(data, data.length);
Arrays.sort(copy);
return (copy.length % 2 != 0) ? copy[copy.length / 2] : (copy[copy.length / 2] + copy[(copy.length / 2) - 1]) / 2;
}
If you only care about unimodal distributions, consider sth. like this.
public static Optional<Integer> mode(Stream<Integer> stream) {
Map<Integer, Long> frequencies = stream
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
return frequencies.entrySet().stream()
.max(Comparator.comparingLong(Map.Entry::getValue))
.map(Map.Entry::getKey);
}
public class Mode {
public static void main(String[] args) {
int[] unsortedArr = new int[] { 3, 1, 5, 2, 4, 1, 3, 4, 3, 2, 1, 3, 4, 1 ,-1,-1,-1,-1,-1};
Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();
for (int i = 0; i < unsortedArr.length; i++) {
Integer value = countMap.get(unsortedArr[i]);
if (value == null) {
countMap.put(unsortedArr[i], 0);
} else {
int intval = value.intValue();
intval++;
countMap.put(unsortedArr[i], intval);
}
}
System.out.println(countMap.toString());
int max = getMaxFreq(countMap.values());
List<Integer> modes = new ArrayList<Integer>();
for (Entry<Integer, Integer> entry : countMap.entrySet()) {
int value = entry.getValue();
if (value == max)
modes.add(entry.getKey());
}
System.out.println(modes);
}
public static int getMaxFreq(Collection<Integer> valueSet) {
int max = 0;
boolean setFirstTime = false;
for (Iterator iterator = valueSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
if (!setFirstTime) {
max = integer;
setFirstTime = true;
}
if (max < integer) {
max = integer;
}
}
return max;
}
}
Test data
Modes {1,3} for { 3, 1, 5, 2, 4, 1, 3, 4, 3, 2, 1, 3, 4, 1 };
Modes {-1} for { 3, 1, 5, 2, 4, 1, 3, 4, 3, 2, 1, 3, 4, 1 ,-1,-1,-1,-1,-1};
As already pointed out by Nico Huysamen, finding multiple mode in Java 1.8 can be done alternatively as below.
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
public static void mode(List<Integer> numArr) {
Map<Integer, Integer> freq = new HashMap<Integer, Integer>();;
Map<Integer, List<Integer>> mode = new HashMap<Integer, List<Integer>>();
int modeFreq = 1; //record the highest frequence
for(int x=0; x<numArr.size(); x++) { //1st for loop to record mode
Integer curr = numArr.get(x); //O(1)
freq.merge(curr, 1, (a, b) -> a + b); //increment the frequency for existing element, O(1)
int currFreq = freq.get(curr); //get frequency for current element, O(1)
//lazy instantiate a list if no existing list, then
//record mapping of frequency to element (frequency, element), overall O(1)
mode.computeIfAbsent(currFreq, k -> new ArrayList<>()).add(curr);
if(modeFreq < currFreq) modeFreq = currFreq; //update highest frequency
}
mode.get(modeFreq).forEach(x -> System.out.println("Mode = " + x)); //pretty print the result //another for loop to return result
}
Happy coding!
Here's the complete clean and optimised code in JAVA 8
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) {
/*Take input from user*/
Scanner sc = new Scanner(System.in);
int n =0;
n = sc.nextInt();
int arr[] = new int[n];
//////////////mean code starts here//////////////////
int sum = 0;
for(int i=0;i<n; i++)
{
arr[i] = sc.nextInt();
sum += arr[i];
}
System.out.println((double)sum/n);
//////////////mean code ends here//////////////////
//////////////median code starts here//////////////////
Arrays.sort(arr);
int val = arr.length/2;
System.out.println((arr[val]+arr[val-1])/2.0);
//////////////median code ends here//////////////////
//////////////mode code starts here//////////////////
int maxValue=0;
int maxCount=0;
for(int i=0; i<n; ++i)
{
int count=0;
for(int j=0; j<n; ++j)
{
if(arr[j] == arr[i])
{
++count;
}
if(count > maxCount)
{
maxCount = count;
maxValue = arr[i];
}
}
}
System.out.println(maxValue);
//////////////mode code ends here//////////////////
}
}

Categories