Lambda and Generic Methods - java

I am learning Lambda and I came across something I cannot solve.
Originally my code was:
package Lambdas;
#FunctionalInterface
interface NumericFunc2 {
<T extends Number> T func(T n);
}
class Lbd_488_NumericFunc_SelfTest {
public static void main(String args[]) {
// This block lambda returns the smallest positive factor of a value.
NumericFunc2 smallestF = (n) -> {
double result = 1;
// Get absolute value of n.
n = n < 0 ? -n : n;
for (int i = 2; i <= n / i; i++)
if ((n % i) == 0) {
result = i;
break;
}
return result;
};
System.out.println("Smallest factor of 12 is " + smallestF.func(12));
System.out.println("Smallest factor of 11 is " + smallestF.func(11));
}
}
However, I keep getting errors next to my operators (<, -, /).
PS:Even if I change it to <T extends Double> I get the same errors.
Now, if I change the code by adding the parameter type, I get an error saying that the "Target Method is Generic":
Even if I change it to <T extends Double> I get the same errors.
package Lambdas;
#FunctionalInterface
interface NumericFunc2 {
<T extends Number> T func(T n);
}
class Lbd_488_NumericFunc_SelfTest {
public static void main(String args[]) {
// This block lambda returns the smallest positive factor of a value.
NumericFunc2 smallestF = (Double n) -> {
double result = 1;
// Get absolute value of n.
n = n < 0 ? -n : n;
for (int i = 2; i <= n / i; i++)
if ((n % i) == 0) {
result = i;
break;
}
return result;
};
System.out.println("Smallest factor of 12 is " + smallestF.func(12));
System.out.println("Smallest factor of 11 is " + smallestF.func(11));
}
}
But, if I change the class from non-generic to generic, everything works fine, like this code:
package Lambdas;
#FunctionalInterface
interface NumericFunc2<T extends Number> {
T func(T n);
}
class Lbd_488_NumericFunc_SelfTest {
public static void main(String args[]) {
// This block lambda returns the smallest positive factor of a value.
NumericFunc2<Double> smallestF = (n) -> {
double result = 1;
// Get absolute value of n.
n = n < 0 ? -n : n;
for (int i = 2; i <= n / i; i++)
if ((n % i) == 0) {
result = i;
break;
}
return result;
};
System.out.println("Smallest factor of 12 is " + smallestF.func(12));
System.out.println("Smallest factor of 11 is " + smallestF.func(11));
}
}
So, my question is. What I am doing work on my first part of the code? How can I use lambdas with generic methods, inside non-generic classes properly?

The answer is that you cannot do this sort of numeric operation on a Number object. There is no way; this has nothing to do with lambdas and everything to do with the Number abstract class just not providing those features.
There is not even any way to get the absolute value of a Number without knowing what kind of Number it is. You can't see whether it's positive or negative, you can't negate it, you can't add, subtract, or multiply it. The only thing you can do with a Number is convert it into another primitive type, but you can't convert it back and you can't do math with it.

According to the JLS, generics and lambdas won't work together. This eclipse bug report discusses it with some code examples.
In order to make it work, you have to fall back to anonymous inner classes. I.e. you have to write the full new NumberFunc() {...} mambo-jambo around your function.
I had to make some other changes in the body of the method to make it compile:
result is the boxed Double so I can cast it to T
inside of the method I'm using the doubleValue() of n because primitive operators won't work on T extends Number.
Putting it together:
class Lbd_488_NumericFunc_SelfTest {
public static void main(String args[]) {
// This block lambda returns the smallest positive factor of a value.
NumericFunc2 smallestF = new NumericFunc2() {
public <T extends Number> T func(T n) {
Double result = 1d;
// Get absolute value of n.
double nAbs = n.doubleValue() < 0 ? -n.doubleValue() : n.doubleValue();
for (int i = 2; i <= nAbs / i; i++)
if ((nAbs % i) == 0) {
result = (double) i;
break;
}
return (T) result;
}
};
System.out.println("Smallest factor of 12 is " + smallestF.func(12));
System.out.println("Smallest factor of 11 is " + smallestF.func(11));
}
}

Related

Converting a number to a user chosen base

I want to make a thing that takes in a number, and a base system, such that it will convert the number to that number in a different base from base 2 to base 16.
E.g. stdin would be 67 and 2, meaning the user wants the program to change the number 67 into binary form. stdout would be 1000010.
So I made the following code to get it going at first. This program takes in a number and converts it to binary format.
public class ChangeofBase {
public static void main(String[] args) {
// read in the command-line argument
int n = Integer.parseInt(args[0]);
// set v to the largest power of two that is <= n
int v = 1;
while (v <= n/2) {
v *= 2;
}
// check for presence of powers of 2 in n, from largest to smallest
while (v > 0) {
// v is not present in n
if (n < v) {
System.out.print(0);
}
// v is present in n, so remove v from n
else {
System.out.print(1);
n -= v;
}
// next smallest power of 2
v /= 2;
}
System.out.println();
}
}
How can I modify the above code to perform the following function?
Take in a number n and a base k so that n will be converted to a number in base k
Once again, k has to be between 2 and 16. Base 2 and base 16. Binary and hexadecimal. Thank you!
Edit: I would like to do this without using built-in functions. Hardcoding
Edit 2: I am new to Java. So I would like to stick to the basic stuff such as defining variables, while loops and foor loops, if-else, and printing. and parsing command line args. I believe thats all we need for this program, though correct me if i'm wrong
You can use Integer.toString(int i, int radix).
Apart from the Java built in function, You can use simple division and modulus operations in Java to achieve that.
public class IntBaseConverter {
public static void main(String[] args) {
convert(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
}
public static void convert(int decimalValue, int base) {
String result = "";
while (decimalValue >= base) {
result = decimalValue % base + result;
decimalValue /= base;
}
result = decimalValue + result;
System.out.println(result);
}
}

Codility PermMissingElem gives strange results

The task is the following:
A zero-indexed array A consisting of N different integers is given. The array contains integers in the range [1..(N + 1)], which means that exactly one element is missing.
Your goal is to find that missing element.
Write a function:
class Solution { public int solution(int[] A); }
that, given a zero-indexed array A, returns the value of the missing element.
For example, given array A such that:
A[0] = 2
A[1] = 3
A[2] = 1
A[3] = 5
the function should return 4, as it is the missing element.
Assume that:
N is an integer within the range [0..100,000];
the elements of A are all distinct;
each element of array A is an integer within the range [1..(N + 1)].
Complexity:
expected worst-case time complexity is O(N);
expected worst-case space complexity is O(1), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.
Now, my solution is the following:
// you can also use imports, for example:
// import java.util.*;
// you can use System.out.println for debugging purposes, e.g.
// System.out.println("this is a debug message");
class Solution {
public int solution(int[] A) {
long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
long arraySum = 0;
for (int element : A)
arraySum += element;
return (int)(nPlusOneSum - arraySum);
}
}
the problem is that i have the following results:
I don't quite understand why I'm having those results in large_range and large2 tests.
I made a sort of a test myself which should simulate large array:
import org.junit.Before;
import org.junit.Test;
public class SomeOtherTest {
int[] maxArray;
int N = 100000;
#Before
public void setUp() {
maxArray = new int[N];
for (int i = 0; i < maxArray.length; i ++) {
maxArray[i] = i + 1;
}
maxArray[0] = maxArray.length + 1;
}
#Test
public void test() {
System.out.println(solution(maxArray));
}
public int solution(int[] A) {
long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
long arraySum = 0;
for (int element : A)
arraySum += element;
return (int)(nPlusOneSum - arraySum);
}
}
but it provides me the correct answer which is 1 (used jdk 1.8 something as in codility)
A link to the test results: https://codility.com/demo/results/demoWAS9FA-5FA/
EDIT:
this solution:
class Solution {
public int solution(int[] A) {
long nPlusOneSum = (A.length + 2) * (A.length + 1) / 2;
for (int element : A)
nPlusOneSum -= element;
return (int)nPlusOneSum;
}
}
gives the same result: https://codility.com/demo/results/demoWAS9FA-5FA/
EDIT2
as soon as I introduced temporary variable to hold array length, test passed
code:
class Solution {
public int solution(int[] A) {
long numberOfElementsPlusOne = A.length + 1;
long nPlusOneSum = numberOfElementsPlusOne * (numberOfElementsPlusOne + 1) / 2;
for (int element : A)
nPlusOneSum -= element;
return (int)nPlusOneSum;
}
}
result: https://codility.com/demo/results/demoE82PUM-JCA/
EDIT3
the weird thing is that test still produces correct results, even despite that during it evaluation, overflow occurs.
nPlusOneSum gets overflowed and gets value 705182705 instead of 5000150001.
arraySum doesn't get overflowed and gets value of 5000150000
Then at return statement nPlusOneSum - arraySum is evaluated to -4294967295 which for some reason is then by conversion to (int) gets the correct value 1.
What happens exactly when operation overflows it's type in java?
The trick is that A.length is integer. You should convert it to long before using.
public int solution(int[] A) {
long sum = 0;
for (int element: A) {
sum += element;
}
long expectedSum = (((long) A.length + 1) * ((long) A.length + 2)) / 2;
return (int) (expectedSum - sum);
}
According to java lang spec:
http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17
The type of a multiplicative expression is the promoted type of its
operands
So resulting type of multiplication of two int is also an int which silently overflows for values around 100.000, the solution would be to change type of operands to long.
EDIT
the weird thing is that test still produces correct results, even despite that during it evaluation, overflow occurs.
There is small catch over here and Its:
Suppose length of your arrays is 100,000. You are trying to find the sum using the formula (N * (N+1))/2, that mean (100,000 * 100,101)/2. So here it multiplies both the numbers first which already exceeded the Max data type value. Hence you have seen the error.
public int solution(int[] arr) {
int realLen = arr.length + 1;
long realSum = 0;
if(realLen%2 == 0) {
realSum = (realLen/2) * (realLen + 1);
} else {
realSum = realLen * ((realLen + 1)/2);
}
for(int i = 0; i < arr.length; i++) {
realSum = realSum - arr[i];
}
return (int)realSum;
}

Memoization with recursive method in java

I am working on a homework assignment, and I have completely exhausted myself. I'm new to programming, and this is my first programming class.
this is the problem:
Consider the following recursive function in Collatz.java, which is related to a famous unsolved problem in number theory, known as the Collatz problem or the 3n + 1 problem.
public static void collatz(int n) {
StdOut.print(n + " ");
if (n == 1) return;
if (n % 2 == 0) collatz(n / 2);
else collatz(3*n + 1);}
For example, a call to collatz(7) prints the sequence
7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
as a consequence of 17 recursive calls. Write a program that takes a command-line argument N and returns the value of n < N for which the number of recursive calls for collatz(n) is maximized. Hint: use memoization. The unsolved problem is that no one knows whether the function terminates for all positive values of n (mathematical induction is no help because one of the recursive calls is for a larger value of the argument).
I have tried several things: using a for loop, trying to count the number of executions with a variable incremented each time the method executed, and hours of drudgery.
Apparently, I'm supposed to use an array somehow with the memoization. However, I don't understand how I could use an array when an array's length must be specified upon initiation.
Am I doing something completely wrong? Am I misreading the question?
Here is my code so far. It reflects an attempt at trying to create an integer array:
public class Collatz2 {
public static int collatz2(int n)
{
StdOut.print(n + " ");
if (n==1) {return 1;}
else if (n==2) {return 1;}
else if (n%2==0) {return collatz2(n/2);}
else {return collatz2(3*n+1);}
}
public static void main(String[] args)
{
int N = Integer.parseInt(args[0]);
StdOut.println(collatz2(N));
}
}
EDIT:
I wrote a separate program
public class Count {
public static void main(String[] args) {
int count = 0;
while (!StdIn.isEmpty()) {
int value = StdIn.readInt();
count++;
}
StdOut.println("count is " + count);
}
}
I then used piping: %java Collatz2 6 | java Count
and it worked just fine.
Since you are interested in the maximum sequence size and not necessarily the sequence itself, it is better to have collatz return the size of the sequence.
private static final Map<Integer,Integer> previousResults = new HashMap<>();
private static int collatz(int n) {
int result = 1;
if(previousResults.containsKey(n)) {
return previousResults.get(n);
} else {
if(n==1) result = 1;
else if(n%2==0) result += collatz(n/2);
else result += collatz(3*n + 1);
previousResults.put(n, result);
return result;
}
}
The memoization is implemented by storing sequence sizes for previous values of n in Map previousResults.
You can look for the maximum in the main function:
public static void main(String[] args) {
int N = Integer.parseInt(args[0]);
int maxn=0, maxSize=0;
for(int n=N; n>0; n--) {
int size = collatz(n);
if(size>maxSize) {
maxn = n;
maxSize = size;
}
}
System.out.println(maxn + " - " + maxSize);
}
The trick here is to write a recursive method where an argument is the value you want to "memoize". For instance, here is a version of a method which will return the number of steps needed to reach 1 (it supposes that n is greater than or equal to 1, of course):
public int countSteps(final int n)
{
return doCollatz(0, n);
}
public static int doCollatz(final int nrSteps, final int n)
{
if (n == 1)
return nrSteps;
final int next = n % 2 == 0 ? n / 2 : 3 * n + 1;
return doCollatz(nrSteps + 1, next);
}
If you were to record the different steps instead, you'd pass a List<Integer> as an argument and .add() to it as you went through, etc etc.

Why aren't my objects that implement Comparable sorted?

my simple example (compiled working code) just does not sort fruits by their weight.
import java.util.Arrays;
public class Test {
public static class Fruit implements Comparable<Fruit> {
public int weight = 0;
public Fruit(int w) { weight = w; }
// compare this fruit to a given fruit f
public int compareTo(Fruit f) {
return (weight > f.weight) ? 1 : 0;
}
}
public static void main(String[] args) {
// get some fruits (we intentionally create a box for 100 fruits)
Fruit[] fruits = new Fruit[100];
for (int i = 0; i < 10; i++) {
fruits[i] = new Fruit((int)(Math.random() * 50 + 1));
}
// sort fruits by weight
Arrays.sort(fruits, 0, 10);
// print fruit weights
for (int i = 0; i < 10; i++) {
System.out.print(fruits[i].weight + " ");
}
}
}
Why it is so?
Alright, in my problem (not about fruits), I have objects that are never pairwise equal, that is why I thought one object is either bigger or smaller than another. So how can I handle this situation when I know that 0 (objects are equal) will never happen?
compareTo must return one of 3 values:
>0 --> Bigger than
0 --> Equal
<0 --> Less than
Your compareTo method only returns 0 or 1; fix that.
Use the method public static int compare(int x, int y) from the class java.lang.Integer (since Java 7).
public int compareTo(Fruit f) {
return Integer.compare(weight, f.weight);
}
If weight is never negative then you can try
return weight - f.weight;
instead of
return (weight > f.weight) ? 1 : 0;
to sort from lowest to highest value.
The best approach is to use the JDK-supplied method for comparing int values, which also makes it crystal clear what the code is doing
public int compareTo(Fruit f) {
return Integer.compare(weight, f.weight);
}
Prior to version 7 java, you have two choices:
public int compareTo(Fruit f) {
return weight - f.weight; // terse, but slightly obtuse
}
public int compareTo(Fruit f) {
return new Integer(weight).compareTo(f.weight); // ugly, but supposedly clear
}
My preference is the subtraction, because once you understand it, it's clear from then on.
Your compareTo method should return -1, 0, 1
LESSER = -1;
EQUAL = 0;
BIGGER = 1;

How to calculate the median of an array?

I'm trying to calculate the total, mean and median of an array thats populated by input received by a textfield. I've managed to work out the total and the mean, I just can't get the median to work. I think the array needs to be sorted before I can do this, but I'm not sure how to do this. Is this the problem, or is there another one that I didn't find? Here is my code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.*;
import java.awt.event.*;
public class whileloopq extends Applet implements ActionListener
{
Label label;
TextField input;
int num;
int index;
int[] numArray = new int[20];
int sum;
int total;
double avg;
int median;
public void init ()
{
label = new Label("Enter numbers");
input = new TextField(5);
add(label);
add(input);
input.addActionListener(this);
index = 0;
}
public void actionPerformed (ActionEvent ev)
{
int num = Integer.parseInt(input.getText());
numArray[index] = num;
index++;
if (index == 20)
input.setEnabled(false);
input.setText("");
sum = 0;
for (int i = 0; i < numArray.length; i++)
{
sum += numArray[i];
}
total = sum;
avg = total / index;
median = numArray[numArray.length/2];
repaint();
}
public void paint (Graphics graf)
{
graf.drawString("Total = " + Integer.toString(total), 25, 85);
graf.drawString("Average = " + Double.toString(avg), 25, 100);
graf.drawString("Median = " + Integer.toString(median), 25, 115);
}
}
The Arrays class in Java has a static sort function, which you can invoke with Arrays.sort(numArray).
Arrays.sort(numArray);
double median;
if (numArray.length % 2 == 0)
median = ((double)numArray[numArray.length/2] + (double)numArray[numArray.length/2 - 1])/2;
else
median = (double) numArray[numArray.length/2];
Sorting the array is unnecessary and inefficient. There's a variation of the QuickSort (QuickSelect) algorithm which has an average run time of O(n); if you sort first, you're down to O(n log n). It actually finds the nth smallest item in a list; for a median, you just use n = half the list length. Let's call it quickNth (list, n).
The concept is that to find the nth smallest, choose a 'pivot' value. (Exactly how you choose it isn't critical; if you know the data will be thoroughly random, you can take the first item on the list.)
Split the original list into three smaller lists:
One with values smaller than the pivot.
One with values equal to the pivot.
And one with values greater than the pivot.
You then have three cases:
The "smaller" list has >= n items. In that case, you know that the nth smallest is in that list. Return quickNth(smaller, n).
The smaller list has < n items, but the sum of the lengths of the smaller and equal lists have >= n items. In this case, the nth is equal to any item in the "equal" list; you're done.
n is greater than the sum of the lengths of the smaller and equal lists. In that case, you can essentially skip over those two, and adjust n accordingly. Return quickNth(greater, n - length(smaller) - length(equal)).
Done.
If you're not sure that the data is thoroughly random, you need to be more sophisticated about choosing the pivot. Taking the median of the first value in the list, the last value in the list, and the one midway between the two works pretty well.
If you're very unlucky with your choice of pivots, and you always choose the smallest or highest value as your pivot, this takes O(n^2) time; that's bad. But, it's also very unlikely if you choose your pivot with a decent algorithm.
Sample code:
import java.util.*;
public class Utility {
/****************
* #param coll an ArrayList of Comparable objects
* #return the median of coll
*****************/
public static <T extends Number> double median(ArrayList<T> coll, Comparator<T> comp) {
double result;
int n = coll.size()/2;
if (coll.size() % 2 == 0) // even number of items; find the middle two and average them
result = (nth(coll, n-1, comp).doubleValue() + nth(coll, n, comp).doubleValue()) / 2.0;
else // odd number of items; return the one in the middle
result = nth(coll, n, comp).doubleValue();
return result;
} // median(coll)
/*****************
* #param coll a collection of Comparable objects
* #param n the position of the desired object, using the ordering defined on the list elements
* #return the nth smallest object
*******************/
public static <T> T nth(ArrayList<T> coll, int n, Comparator<T> comp) {
T result, pivot;
ArrayList<T> underPivot = new ArrayList<>(), overPivot = new ArrayList<>(), equalPivot = new ArrayList<>();
// choosing a pivot is a whole topic in itself.
// this implementation uses the simple strategy of grabbing something from the middle of the ArrayList.
pivot = coll.get(n/2);
// split coll into 3 lists based on comparison with the pivot
for (T obj : coll) {
int order = comp.compare(obj, pivot);
if (order < 0) // obj < pivot
underPivot.add(obj);
else if (order > 0) // obj > pivot
overPivot.add(obj);
else // obj = pivot
equalPivot.add(obj);
} // for each obj in coll
// recurse on the appropriate list
if (n < underPivot.size())
result = nth(underPivot, n, comp);
else if (n < underPivot.size() + equalPivot.size()) // equal to pivot; just return it
result = pivot;
else // everything in underPivot and equalPivot is too small. Adjust n accordingly in the recursion.
result = nth(overPivot, n - underPivot.size() - equalPivot.size(), comp);
return result;
} // nth(coll, n)
public static void main (String[] args) {
Comparator<Integer> comp = Comparator.naturalOrder();
Random rnd = new Random();
for (int size = 1; size <= 10; size++) {
ArrayList<Integer> coll = new ArrayList<>(size);
for (int i = 0; i < size; i++)
coll.add(rnd.nextInt(100));
System.out.println("Median of " + coll.toString() + " is " + median(coll, comp));
} // for a range of possible input sizes
} // main(args)
} // Utility
If you want to use any external library here is Apache commons math library using you can calculate the Median.
For more methods and use take look at the API documentation
import org.apache.commons.math3.*;
.....
......
........
//calculate median
public double getMedian(double[] values){
Median median = new Median();
double medianValue = median.evaluate(values);
return medianValue;
}
.......
For more on evaluate method AbstractUnivariateStatistic#evaluate
Update
Calculate in program
Generally, median is calculated using the following two formulas given here
If n is odd then Median (M) = value of ((n + 1)/2)th item term.
If n is even then Median (M) = value of [((n)/2)th item term + ((n)/2 + 1)th item term ]/2
In your program you have numArray, first you need to sort array using Arrays#sort
Arrays.sort(numArray);
int middle = numArray.length/2;
int medianValue = 0; //declare variable
if (numArray.length%2 == 1)
medianValue = numArray[middle];
else
medianValue = (numArray[middle-1] + numArray[middle]) / 2;
Arrays.sort(numArray);
return (numArray[size/2] + numArray[(size-1)/2]) / 2;
Arrays.sort(numArray);
int middle = ((numArray.length) / 2);
if(numArray.length % 2 == 0){
int medianA = numArray[middle];
int medianB = numArray[middle-1];
median = (medianA + medianB) / 2;
} else{
median = numArray[middle + 1];
}
EDIT: I initially had medianB setting to middle+1 in the even length arrays, this was wrong due to arrays starting count at 0. I have updated it to use middle-1 which is correct and should work properly for an array with an even length.
You can find good explanation at https://www.youtube.com/watch?time_continue=23&v=VmogG01IjYc
The idea it to use 2 Heaps viz one max heap and mean heap.
class Heap {
private Queue<Integer> low = new PriorityQueue<>(Comparator.reverseOrder());
private Queue<Integer> high = new PriorityQueue<>();
public void add(int number) {
Queue<Integer> target = low.size() <= high.size() ? low : high;
target.add(number);
balance();
}
private void balance() {
while(!low.isEmpty() && !high.isEmpty() && low.peek() > high.peek()) {
Integer lowHead= low.poll();
Integer highHead = high.poll();
low.add(highHead);
high.add(lowHead);
}
}
public double median() {
if(low.isEmpty() && high.isEmpty()) {
throw new IllegalStateException("Heap is empty");
} else {
return low.size() == high.size() ? (low.peek() + high.peek()) / 2.0 : low.peek();
}
}
}
Try sorting the array first. Then after it's sorted, if the array has an even amount of elements the mean of the middle two is the median, if it has a odd number, the middle element is the median.
Use Arrays.sort and then take the middle element (in case the number n of elements in the array is odd) or take the average of the two middle elements (in case n is even).
public static long median(long[] l)
{
Arrays.sort(l);
int middle = l.length / 2;
if (l.length % 2 == 0)
{
long left = l[middle - 1];
long right = l[middle];
return (left + right) / 2;
}
else
{
return l[middle];
}
}
Here are some examples:
#Test
public void evenTest()
{
long[] l = {
5, 6, 1, 3, 2
};
Assert.assertEquals((3 + 4) / 2, median(l));
}
#Test
public oddTest()
{
long[] l = {
5, 1, 3, 2, 4
};
Assert.assertEquals(3, median(l));
}
And in case your input is a Collection, you might use Google Guava to do something like this:
public static long median(Collection<Long> numbers)
{
return median(Longs.toArray(numbers)); // requires import com.google.common.primitives.Longs;
}
I was looking at the same statistics problems. The approach you are thinking it is good and it will work. (Answer to the sorting has been given)
But in case you are interested in algorithm performance, I think there are a couple of algorithms that have better performance than just sorting the array, one (QuickSelect) is indicated by #bruce-feist's answer and is very well explained.
[Java implementation: https://discuss.leetcode.com/topic/14611/java-quick-select ]
But there is a variation of this algorithm named median of medians, you can find a good explanation on this link:
http://austinrochford.com/posts/2013-10-28-median-of-medians.html
Java implementation of this:
- https://stackoverflow.com/a/27719796/957979
I faced a similar problem yesterday.
I wrote a method with Java generics in order to calculate the median value of every collection of Numbers; you can apply my method to collections of Doubles, Integers, Floats and returns a double. Please consider that my method creates another collection in order to not alter the original one.
I provide also a test, have fun. ;-)
public static <T extends Number & Comparable<T>> double median(Collection<T> numbers){
if(numbers.isEmpty()){
throw new IllegalArgumentException("Cannot compute median on empty collection of numbers");
}
List<T> numbersList = new ArrayList<>(numbers);
Collections.sort(numbersList);
int middle = numbersList.size()/2;
if(numbersList.size() % 2 == 0){
return 0.5 * (numbersList.get(middle).doubleValue() + numbersList.get(middle-1).doubleValue());
} else {
return numbersList.get(middle).doubleValue();
}
}
JUnit test code snippet:
/**
* Test of median method, of class Utils.
*/
#Test
public void testMedian() {
System.out.println("median");
Double expResult = 3.0;
Double result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,13.0));
assertEquals(expResult, result);
expResult = 3.5;
result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,4.0,13.0));
assertEquals(expResult, result);
}
Usage example (consider the class name is Utils):
List<Integer> intValues = ... //omitted init
Set<Float> floatValues = ... //omitted init
.....
double intListMedian = Utils.median(intValues);
double floatSetMedian = Utils.median(floatValues);
Note: my method works on collections, you can convert arrays of numbers to list of numbers as pointed here
And nobody paying attention when list contains only one element (list.size == 1). All your answers will crash with index out of bound exception, because integer division returns zero (1 / 2 = 0). Correct answer (in Kotlin):
MEDIAN("MEDIAN") {
override fun calculate(values: List<BigDecimal>): BigDecimal? {
if (values.size == 1) {
return values.first()
}
if (values.size > 1) {
val valuesSorted = values.sorted()
val mid = valuesSorted.size / 2
return if (valuesSorted.size % 2 != 0) {
valuesSorted[mid]
} else {
AVERAGE.calculate(listOf(valuesSorted[mid - 1], valuesSorted[mid]))
}
}
return null
}
},
As #Bruce-Feist mentions, for a large number of elements, I'd avoid any solution involving sort if performance is something you are concerned about. A different approach than those suggested in the other answers is Hoare's algorithm to find the k-th smallest of element of n items. This algorithm runs in O(n).
public int findKthSmallest(int[] array, int k)
{
if (array.length < 10)
{
Arrays.sort(array);
return array[k];
}
int start = 0;
int end = array.length - 1;
int x, temp;
int i, j;
while (start < end)
{
x = array[k];
i = start;
j = end;
do
{
while (array[i] < x)
i++;
while (x < array[j])
j--;
if (i <= j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
} while (i <= j);
if (j < k)
start = i;
if (k < i)
end = j;
}
return array[k];
}
And to find the median:
public int median(int[] array)
{
int length = array.length;
if ((length & 1) == 0) // even
return (findKthSmallest(array, array.length / 2) + findKthSmallest(array, array.length / 2 + 1)) / 2;
else // odd
return findKthSmallest(array, array.length / 2);
}
public static int median(int[] arr) {
int median = 0;
java.util.Arrays.sort(arr);
for (int i=0;i<arr.length;i++) {
if (arr.length % 2 == 1) {
median = Math.round(arr[arr.length/2]);
} else {
median = (arr[(arr.length/2)] + arr[(arr.length/2)-1])/2;
}
}
return median;
}
Check out the Arrays.sort methods:
http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html
You should also really abstract finding the median into its own method, and just return the value to the calling method. This will make testing your code much easier.
public int[] data={31, 29, 47, 48, 23, 30, 21
, 40, 23, 39, 47, 47, 42, 44, 23, 26, 44, 32, 20, 40};
public double median()
{
Arrays.sort(this.data);
double result=0;
int size=this.data.length;
if(size%2==1)
{
result=data[((size-1)/2)+1];
System.out.println(" uneven size : "+result);
}
else
{
int middle_pair_first_index =(size-1)/2;
result=(data[middle_pair_first_index+1]+data[middle_pair_first_index])/2;
System.out.println(" Even size : "+result);
}
return result;
}
package arrays;
public class Arraymidleelement {
static public double middleArrayElement(int [] arr)
{
double mid;
if(arr.length%2==0)
{
mid=((double)arr[arr.length/2]+(double)arr[arr.length/2-1])/2;
return mid;
}
return arr[arr.length/2];
}
public static void main(String[] args) {
int arr[]= {1,2,3,4,5,6};
System.out.println( middleArrayElement(arr));
}
}

Categories

Resources