I want to create generic method for getting maximal value from the array. However I got stuck at the problem of conversion between T to type Math.max method uses.
here is my code:
First I cannot initialize the maxValue like:
T maxVaue = 0;
secondly I cannot use data[i] in Math.max, in both cases I got error of In convertible cast.
class Matrix<T>{
public T getMaxValue(T[] data){
T maxValue;
for (int i=0; i<data.length; i++){
maxValue = Math.max(data[i], maxValue);
}
return maxValue;
}
}
Math.max takes only int, float, double and long. So you can not use it with T.
What you can do is write your own max() method using T. For example, your method could take a Comparator object in param. Or your T objects can implement the Comparable interface.
Have a look at this post : How to implement a generic `max(Comparable a, Comparable b)` function in Java?
You cannot do that as you are doing it because a T can be anything. You could e.g. limit T to a Number but then you'd have to choose an intermediate primitive type and you will still run into issues returning the value.
However, you could just limit T to Comparable and use that instead, e.g.:
class Matrix<T extends Comparable<T>>{
public T getMaxValue(T[] data){
T maxValue = null;
for (int i=0; i<data.length; i++){
if (maxValue == null || data[i].compareTo(maxValue) > 0)
maxValue = data[i];
}
return maxValue;
}
}
All of Java's primitive wrapper types implement Comparable, as well as many other types:
byte by = new Matrix<Byte>().getMaxValue(new Byte[]{1, 2, 3});
char ch = new Matrix<Character>().getMaxValue(new Character[]{'a', 'b', 'c'});
int in = new Matrix<Integer>().getMaxValue(new Integer[]{1, 2, 3});
short sh = new Matrix<Short>().getMaxValue(new Short[]{1, 2, 3});
long lo = new Matrix<Long>().getMaxValue(new Long[]{1L, 2L, 3L});
float fl = new Matrix<Float>().getMaxValue(new Float[]{0.1f, 0.2f, 0.3f});
double db = new Matrix<Double>().getMaxValue(new Double[]{0.1, 0.2, 0.3});
boolean bo = new Matrix<Boolean>().getMaxValue(new Boolean[]{false, true});
String st = new Matrix<String>().getMaxValue(new String[]{"turtles", "are", "weird"});
BigInteger bi = new Matrix<BigInteger>().getMaxValue(new BigInteger[]{...});
T can hold only classes like Double, Integer, not primitive types like double, int. Maybe just use built-in Collections.max(Collection<T extends Comparable<T>>) and array of Doubles instead of doubles like in this code example
class Matrix<T extends Comparable<T>> {
public T getMaxValue(T[] data) {
return Collections.max(Arrays.asList(data));
}
public static void main(String[] args) throws IOException {
Matrix<Double> m = new Matrix<>();
System.out.println(m.getMaxValue(new Double[] { 1., 42., 3., 4., 5. }));
}
}
Related
This is basically to avoid redundant code. I have two different arrays, one of Float type and one Integer type. I need to find index of maximum element in both the arrays which is easy to do as I can write two different methods, one for comparing float and one for comparing Integers.
What am trying to do improve is to write just one common method which can take in either of the array as argument and can return me the max index. What I have tried unsuccessfully so far is:
private static int findMaxIndex(Object [] arr){
int maxIndex =(int) IntStream.range(0,arr.length)
.boxed()
.max(Comparator.comparingInt(i -> arr[i])) // getting compiler error here
.map(max->arr[max])
.orElse(-1);
return maxIndex;
}
and am looking to call this method like this:
Float [] a = {0.3f, 0.5f, 0.9f, 0.7f, 0.1f};
Integer []b = {3000, 250, 100, 2000, 2000, 10246};
int maxIndexFloatArray = findMaxIndex(a);
int maxIndexIntegerArray = findMaxIndex(b);
Am pretty sure there are easier ways to do this, but am a bit rusty now in hands on java code. Hope this explains the question correctly.
lambda with reduce comparing Comparables
private static <T extends Comparable<? super T>> int findMaxIndex(T[] arr) {
return IntStream.range(0, arr.length)
.reduce((l, r) -> arr[l].compareTo(arr[r]) < 0 ? r : l).orElse(-1);
}
for multiple max values the index of the first is returned
if You need the index of the last max value change the < to <=
arr can be empty but may not contain null values
You could do it old fashioned:
private <T> int findMaxIndex(T[] arr, Comparator<T> comparator){
int maxIndex= 0;
T currMax = arr[0];
for (int i=1;i<arr.length;i++){
if (comparator.compare(currMax,arr[i])<0){
currMax = arr[i];
maxIndex = i;
}
}
return maxIndex;
}
And then call it like:
private int getMaxFloatIndex(Float[] floatArr){
return findMaxIndex(floatArr,Float::compareTo);
}
Grabbing the inheritance hierarchy "from top", I would propose Comparable<X> as the input type for findMaxIndex. It is the most general type of object, of which you can distinguish a "max element":
private static <X extends Comparable<X>> int findMaxIndex(final X[] arr) {
return IntStream.range(0, arr.length)
.boxed()
.max(
(Integer idx1, Integer idx2) -> arr[idx1].compareTo(arr[idx2])
)
.orElse(-1);
}
For simplicity: Hoping/assuming arr is nor null nor contains null elements! ;) (otherwise: NPE!)
...to use it like:
Float[] a = { 0.3f, 0.5f, 0.9f, 0.7f, 0.1f };
Integer[] b = { 3000, 250, 100, 2000, 2000, 10246 };
System.out.println(findMaxIndex(a));
System.out.println(findMaxIndex(b));
Prints:
2
5
This one should do the trick:
private static <T extends Number & Comparable<T>> int findMaxIndex(T[] array) {
if (array == null || array.length == 0) return -1;
int largest = 0;
for (int i = 1; i < array.length; i++) {
if (array[i].compareTo(array[largest]) > 0) largest = i;
}
return largest;
}
You literally tell the compiler that your generic parameter T should be both a Number and Comparable to the same type.
<T extends Number & Comparable<T>> int findMaxIndex(T[] arr)
This can find the index of the maximal value based on Number, the interface of all numeric types, wrapper classes and atomic wrappers.
Also a findMax might so be made. Without the numeric aspect, just Comparable suffices, say for a String[].
I have a class Test and a method testMethod. I try to pass an int and an array of type T to the method, and it should return the int'th element of the array.
public class Test {
public static void main(String[] args) {
System.out.println(testMethod(1, new int[] {1,2,4}));
}
public static <T> T testMethod(int rank, T[] elements) {
return elements[rank];
}
}
However I get a _method testMethodin class Test cannot be applied to given types_, T extends Object declared in method <T>testMethod(int,T[]).
I guess the issue is that the array is of basic type int. I tried changing it to Integer and it worked.
Is there a way to make it work, while still using basic numeric types like int or double or float?
You have to overload the testMethod(int, T[]) method to pass an int[] array:
public static int testMethod(int rank, int[] elements) {
return elements[rank];
}
Otherwise, you need to meet requirements of T[], T extends Object (which denies primitive types) and pass an Integer[] array:
public static <T> T testMethod(int rank, T[] elements) {
return elements[rank];
}
Now you can pass either int[] or Integer[]:
final Integer i1 = testMethod(1, new Integer[]{1, 2, 4});
final int i2 = testMethod(1, new int[]{1, 2, 4});
Is there a way to make it work, while still using basic numeric types like int or double or float?
Unfortunately, only by method overloading. Have a look at the Arrays.binarySearch methods (18 different signatures in there). Most of the signatures were designed only to cover all the types.
Would overloading require just copying the code from the main function though?
I am afraid, yes (with small type and naming changes). Find the difference :)
public static void parallelSort(long[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
int n = toIndex - fromIndex, p, g;
if (n <= MIN_ARRAY_SORT_GRAN ||
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
else
new ArraysParallelSortHelpers.FJLong.Sorter
(null, a, new long[n], fromIndex, n, 0,
((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
MIN_ARRAY_SORT_GRAN : g).invoke();
}
public static void parallelSort(float[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
int n = toIndex - fromIndex, p, g;
if (n <= MIN_ARRAY_SORT_GRAN ||
(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); // 1
else
new ArraysParallelSortHelpers.FJFloat.Sorter // 2
(null, a, new float[n], fromIndex, n, 0, // 3
((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
MIN_ARRAY_SORT_GRAN : g).invoke();
}
Is it a good practice to copy paste with little changes such code into several functions?
It is definitely not. But do we have another way?
You could say that primitive boxing might be an option:
final int[] ints = {1, 2, 4};
final Integer i3 = testMethod(1, Arrays.stream(ints).boxed().toArray(Integer[]::new));
But does a good API force users to convert their data to fit the given signatures?
You cannot use a primitive type in place of a generic type parameter.
You can pass an Integer array instead:
System.out.println(testMethod(1, new Integer[] {1,2,4}));
You can't use a primitive in a Generic type because this is not inheriting Object. See more about that in Why don't Java Generics support primitive types?
. For the conversion into an Integer array in your case, you can use the Streamn API do the boxing :
public static Integer[] boxed(int[] array){
return IntStream.of(array).boxed().toArray(Integer[]::new);
}
It is basicily the same as iterating the array and boxing the value... into another instance.
You need to do that each time you want to use a primitive array in a generic method... not perfect but this will allow you to convert every existing array without the need to changing the type of an existing variable (Integer can be null which add other problems).
int[] array = {1,2,4};
System.out.println(testMethod(1, boxed(array)));
EDIT:
Without having to change your calls, simply by overriding the method for the primitve int :
public static int testMethod(int rank, int[] array){
return testMethod(rank, Arrays.stream(array).boxed().toArray(Integer[]::new));
}
public static long testMethod(int rank, long[] array){
return testMethod(rank, Arrays.stream(array).boxed().toArray(Long[]::new));
}
public static double testMethod(int rank, double[] array){
return testMethod(rank, Arrays.stream(array).boxed().toArray(Double[]::new));
}
NOTE: for some type, you will probably be forced to simply build the array with a loop ... this will be a bit more verbose.
I think you already mentioned the solution to make this code work in your question.. the only we is that we have to use Integer instead of int..
public static void main(String[] args) {
System.out.println(testMethod(1, new Integer[] {1,2,4}));
}
public static <T> T testMethod(int rank, T[] elements) {
return elements[rank];
}
If you want to use int, you cannot use T[] and would have to use int[] instead..
This question already has answers here:
java.lang.Number doesn't implement "+" or any other operators?
(6 answers)
Closed 8 years ago.
the following class simulates a generic matrix which can be filled with Ts, where .
public class GenMatrix<T extends Number> {
//local matrix
T[][] matrix;
public GenMatrix(T[][] matrix) {
//if matrix is n x n, set it as local
if (matrix.length == matrix[0].length)
this.matrix = matrix;
}
//multiplies the matrix with a vector of the same type T and returns a Double vector
Double[] multVector (T[] vector){
//check wether the matrix can be multiplied with the vector
if (vector.length != matrix.length) return null;
//new Double vector
Double[] result = new Double[matrix.length];
//matrix - vector -multiplication
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
//cast all Ts into Doubles
result[j] += ((Double)matrix[i][j])*((Double)vector[j]);
}
}
return result;
}
}
As you can see the method multVector(..) returns a Double[].
My question: Why can't it return a T[]? If i dont cast the matrix and vector entries in the calculation to Double, the compiler says " the operator "*" is unknown for the type T". Im wondering about that since T extends Number and Number is a calculatable (isnt it?).
I am not searching for a workaround to return a T[] Vector but for the answere of the "why doesnt it work"-question.
Regards Tak3r07
When something extends Number, you can't necessarily cast it into a Double, Integer or any other child class. Read about the difference between primitive and Object datatypes in Java. The numeric operators only work on the primitive types. What happens when you apply your cast to Double and use the *, Java will perform a process called auto-unboxing.
Your casts can run into ClasscastExceptions. Instead of this
result[j] += ((Double)matrix[i][j])*((Double)vector[j]);
do this:
result[j] += (matrix[i][j].doubleValue())*(vector[j].doubleValue());
Mathematical operators are not defined for Number. They are defined for numeric primitives: byte, short, int, long. The reason that you can say:
Integer i = 5;
int j = i + 2;
is autoboxing that automatically replaces i by i.intValue() in expression i + 2.
This is the reason that you cannot use + operator with generic type T.
Method multVector() can return generic type: T[] multVector(T[] input). To do this you should pass your definition of*` to the method:
interface MathOperator<T> {
perform(T one, T two);
}
class MultiplyDouble implements MathOperator<Double> {
perform(Double one, Double two) {
return one * two;
}
}
T[] multVector (T[] vector, MathOperator<T> operator){...}
Now you can call this method as following:
multVector (new Double[] {1.1, 2.2, 3.3}, new MultiplyDouble());
BTW creating instance of generic array is challenge too. TIP: user class java.lang.reflect.Array.
multVectorcould of course return an array of T. The problems are :
you cannot do operations on a type-variable, nor on Number class
you cannot create an array of type-variable
For the first part, you must know the actual class represented by T. So you should have :
...
T[][] matrix;
Class<T> clazz;
public GenMatrix(T[][] matrix, Class<T> clazz) {
//if matrix is n x n, set it as local
if (matrix.length == matrix[0].length)
this.matrix = matrix;
this.clazz = clazz;
}
...
T[] result = (T[]) Array.newInstance(clazz, matrix.length);
...
For the second, you could keep on making calculations on double and casting at the end:
abstract <T> fromDouble(double value); // to be implemented in actual class
//matrix - vector -multiplication
double res;
for (int j = 0; i < matrix.length; i++) {
res = 0.;
for (int i = 0; j < matrix[0].length; j++) {
//cast all Ts into Doubles
res += matrix[i][j].doubleValue() * vector[j].doubleValue();
}
resul[j] = fromDouble(res);
}
As you see, it is far more complicated for a limited gain.
I need to use Arrays.binarySearch on an array of custom objects. Here is the object:
class Range implements Comparable<Range>{
public int bottom;
public int top;
public Range(int botIn, int topIn) {
this.bottom = botIn;
this.top = topIn;
}
#Override
public int compareTo(Range compareRange) {
int compareQuantity = ((Range) compareRange).bottom;
return this.bottom - compareQuantity;
}}
In my main I first call Arrays.sort(lowerBounds); where lowerBounds is an array of Range elements. This works just fine and sorts them using the compareTo I wrote. Then I call Arrays.binarySearch(lowerBounds, 0) but I get "Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to compareToTest.Range".
What am I doing wrong? Thank you.
Edit: here is main:
public static void main(String[] args)
{
int[] A = {1, 5, 2, 1, 4, 0};
// write your code in Java SE 6
Range[] lowerBounds = new Range[A.length];
for(int i=0; i< A.length; i++)
{
lowerBounds[i] = new Range(i-A[i], i+A[i]);
}
Arrays.sort(lowerBounds);
for(int i=0; i< A.length; i++)
{
System.out.println(lowerBounds[i].bottom);
}
System.out.println(Arrays.binarySearch(lowerBounds, 0));
}
Arrays.binarySearch accepts two parameters - an array to search in, and the object you're looking for. You have supplied an array of Range object and an int (which is autoboxed to an Integer). Naturally, you can't search for an Integer in an array of Ranges.
Instead, you should create the Range object you're looking for. E.g.:
Range r = new Range (0, 0);
Arrays.binarySearch (lowerBounds, r);
Arrays.binarySearch(lowerBounds, 0) is wrong because you are comparing Range Objects.SO you need to pass a Range Object instead of an Integer Object which results in java.lang.ClassCastException: java.lang.Integer cannot be cast to compareToTest.Range"
You need to create a RangeObject and pass it in binarySearch method
Range r = new Range(0,<any integer>)
Arrays.binarySearch (lowerBounds, r);
I want to write a Java function that will get as input either int[], float[] or double[]. The algorithm is exactly the same (some kind of a scalar product). How can I write a single function that will be able to handle all types of numeric arrays?
There is no easy way to handle this in Java. You can:
Use Wrapper types (Integer[], Float[], Double[]) and have a function taking Number[] as an argument. Works since arrays are covariant in Java:
public static void main(String[] args) {
f(new Integer[]{1,2,3});
f(new Float[]{1,2,3});
f(new Double[]{1,2,3});
}
private static void f(Number[] numbers) {
f[0].doubleValue();
}
Note that this approach increases memory consumption significantly.
Convert int[] and float[] arrays to double[] and work with doubles all along. Preferably create overloaded versions of your method where the ones taking int[] and float[] are only doing the conversion and delegate to actual double[] implementation.
I believe Scala can handle this seamlessly as Java primitive types are semantically objects in Scala.
You cannot code this in Java without either:
coding each case separately or,
using reflection for all operations on the array ... which is likely to be messy, fragile and an order of magnitude slower than an optimal solution.
The only common supertype of int[] float[] and double[] is Object, so there is no possibility of a solution using polymorphism over those types. Likewise, generics require that the type parameter is a reference type, and int, float and double are not reference types.
You either need to accept that you will have duplicate code, or change the representation type for the arrays; e.g. use Integer[] / Float[] / Double[] or Number[].
You can write one method to do them all, however, it won't be anywhere near as readable of efficient. You have to make a choice between what is a generic or an efficient solution.
public static void main(String... args) throws IOException {
int[] nums = new int[10*1000 * 1000];
{
long start = System.nanoTime();
product2(nums);
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to take the product of %,d ints using an int[].%n", time / 1e9, nums.length);
}
{
long start = System.nanoTime();
product(nums);
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to take the product of %,d ints using reflections.%n", time / 1e9, nums.length);
}
}
public static double product(Object array) {
double product = 1;
for (int i = 0, n = Array.getLength(array); i < n; i++)
product *= ((Number) Array.get(array, i)).doubleValue();
return product;
}
public static double product2(int... nums) {
double product = 1;
for (int i = 0, n = nums.length; i < n; i++)
product *= nums[i];
return product;
}
prints
Took 0.016 seconds to take the product of 10,000,000 ints using an int[].
Took 0.849 seconds to take the product of 10,000,000 ints using reflections.
If you are only working on relatively small arrays, the generic but less efficient solution may be fast enough.
Use java.lang.Number type or Object parameter type.
For more info read Bounded Type Parameters
I see two options:
1) You can create a new class which allows int[], float[], double[] in the contructor and saves them.
2) You allow Object[] and check for int / float / double. (You have to convert them first)
class ArrayMath {
private ArrayMath() {
}
public static <T extends Number> double ScalarProduct(T[] a, T[] b){
double sum = 0;
for(int i=0;i<a.length;++i){
sum += a[i].doubleValue()*b[i].doubleValue();
}
return sum;
}
}
class Sample {
public static void main(String arg[]){
Integer[] v1 = { 1, -10, 3, 9, 7, 99, -25 };
Integer[] v2 = { 1, -10, 3, 9, 7, 99, -25 };
double p_int = ArrayMath.ScalarProduct(v1, v2);
Double[] v1_d = { 1.1, -10.5, 3.7, 9.98, 7.4, 9.9, -2.5 };
Double[] v2_d = { 1.1, -10.5, 3.7, 9.98, 7.4, 9.9, -2.5 };
Double p_double = ArrayMath.ScalarProduct(v1_d, v2_d);
System.out.println("p_int:" + p_int);
System.out.println("p_double:" + p_double);
}
}
Hope this will help you.. I have tested this code and it does what you have asked for, how to implement this logic is upto you !
public class MultiDataType {
public static void main(String[] args) {
int[] i = new int[2];
float[] f = new float[2];
double[] d = new double[2];
String str = new String();
handlingFunction(i);
handlingFunction(f);
handlingFunction(d);
handlingFunction(str);
}
public static void handlingFunction(Object o) {
String classType = null;
if (o.getClass().getCanonicalName().equals("int[]")) {
classType = "int[]";// Your handling code goes here
} else if (o.getClass().getCanonicalName().equals("float[]")) {
classType = "float[]";// Your handling code goes here
} else if (o.getClass().getCanonicalName().equals("double[]")) {
classType = "double[]";// Your handling code goes here
}else classType = o.getClass().getCanonicalName();
System.out.println("Object belongs to " + classType);
}
}
OUTPUT
Object belongs to int[]
Object belongs to float[]
Object belongs to double[]
Object belongs to java.lang.String