The following Java code compares the average of two arrays, one of Integers and one of Doubles.
class Generic_Class<T extends Number>
{
T[] nums; // array of Number or subclass
Generic_Class(T[] o)
{
nums = o;
}
// Return type double in all cases.
double average()
{
double sum = 0.0;
for(int i=0; i < nums.length; i++)
sum += nums[i].doubleValue();
return sum / nums.length;
}
// boolean sameAvg(Generic_Class<T> ob)
// Using Generic_Class<T> i get the error:
// incompatible types: Generic_Class<Double> cannot be converted to Generic_Class<Integer>
// Using wilcards I get no error
boolean sameAvg(Generic_Class<?> ob)
{
if(average() == ob.average())
return true;
return false;
}
}
The main method is like this:
public static void main(String args[])
{
Integer inums[] = { 1, 2, 3, 4, 5 };
Double dnums[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
Generic_Class<Integer> iob = new Generic_Class<Integer>(inums);
Generic_Class<Double> dob = new Generic_Class<Double>(dnums);
System.out.println("iob average is " + iob.average());
System.out.println("dob average is " + dob.average());
if (iob.sameAvg(dob))
System.out.println("Averages of iob and dob are the same.");
else
System.out.println("Averages of iob and dob differ.");
}
The result is:
iob average is 3.0
dob average is 3.0
Averages of iob and dob are the same.
I've tried to do the same in C# but, since I have no wildcards, I can't accomplish the same task.
How can I do the same with C# ?
Thank you.
As other answerers have said, there is no equivalent of Number in C#. The best you can get is struct, IConvertible. However, there is another way of doing the generic wildcard.
Just use another generic parameter:
public class Generic_Class<T> where T : struct, IConvertible
{
T[] nums;
public Generic_Class(T[] o)
{
nums = o;
}
public double Average()
{
double sum = 0.0;
for(int i=0; i < nums.Length; i++)
sum += nums[i].ToDouble(null);
return sum / nums.Length;
}
// this is the important bit
public bool SameAvg<U>(Generic_Class<U> ob) where U : struct, IConvertible
{
if(Average() == ob.Average())
return true;
return false;
}
}
Taking the average of a sequence of numbers is built-in to C#:
var iNums = new int[] { 1, 2, 3, 4, 5 };
var dNums = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0 };
var iAvg = iNums.Average();
var dAvg = dNums.Average();
var areEqual = iAvg == dAvg;
areEqual == true after running the above.
You can even do this with complex types using the Average overload that takes a Func<TSource, T> to return a value:
public class MyValue
{
private static Random rnd = new Random();
public int SomeInt { get; set; } = rnd.Next();
}
var myObjArray = new MyValue[] { new MyValue(), new MyValue(), new MyValue(), new MyValue() };
var myAvg = myObjArray.Average(o => o.SomeInt);
So no, wildcards are not available in C#, but using Generics you can simulate wildcards by having multiple overloads of the Func in this case.
See IEnumerable Methods
Just add simple interface with method double Average so you can do:
interface IAbleToGetAverage
{
double Average();
}
class GenericClass<T> : IAbleToGetAverage
where T : struct, IConvertible
{
private readonly T[] nums; // array of Number or subclass
public GenericClass(T[] o)
{
nums = o;
}
private readonly IFormatProvider formatProvider = new NumberFormatInfo();
public double Average()
{
var sum = 0.0;
for(var i=0; i < nums.Length; i++)
sum += nums[i].ToDouble(formatProvider);
return sum / nums.Length;
}
public bool SameAvg(IAbleToGetAverage ob)
{
if(Math.Abs(Average() - ob.Average()) < double.Epsilon)
return true;
return false;
}
}
What you're expressing in your Java code is boxed numeric types, which all extend the Number class, so it's trivial to enforce a constraint that the generic type is a number.
Types work a little differently in C# because int rather that being primitive in the same sense as Java, is just a type alias for System.Int32 which is a struct.
Also, there is no common base type (class, struct, interface, etc.) that is shared by ONLY numbers in C#, so its IMPOSSIBLE to create a constraint to enforce that the generic type is a number, has a numeric value, and therefore can have mathematical calculations performed on it.
Some suggestions here seem to be to use where T : IComparable, struct but I could argue that the constraint also applies to DateTime, Guid and TimeSpan - none of which are integral or floating point numbers.
Related
I would like to generically add numbers in java. I'm running into difficulty because the Numbers class doesn't really support what I want to do. What I've tried so far is this:
public class Summer<E extends Number> {
public E sumValue(List<E> objectsToSum) {
E total = (E) new Object();
for (E number : objectsToSum){
total += number;
}
return null;
}
Obviously this will not work. How can I go about correcting this code so I could be given a list of <int> or <long> or whatever and return the sum?
In order to calculate a sum generically, you need to provide two actions:
A way to sum zero items
A way to sum two items
In Java, you do it through an interface. Here is a complete example:
import java.util.*;
interface adder<T extends Number> {
T zero(); // Adding zero items
T add(T lhs, T rhs); // Adding two items
}
class CalcSum<T extends Number> {
// This is your method; it takes an adder now
public T sumValue(List<T> list, adder<T> adder) {
T total = adder.zero();
for (T n : list){
total = adder.add(total, n);
}
return total;
}
}
public class sum {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(4);
list.add(8);
CalcSum<Integer> calc = new CalcSum<Integer>();
// This is how you supply an implementation for integers
// through an anonymous implementation of an interface:
Integer total = calc.sumValue(list, new adder<Integer>() {
public Integer add(Integer a, Integer b) {
return a+b;
}
public Integer zero() {
return 0;
}
});
System.out.println(total);
}
}
As Number class does not expose interface for performing calculations, the only way to solve this problem is to create classes which encapsulates required operations for each supported numeric type. Than in your class you will need to use specific type.
Number has intValue(), floatValue(), doubleValue(), longValue, and shortValue(). Choose one and use it. For example,
double total;
total += number.doubleValue();
return total;
Also, java generics are in no way equivalent to c++ templates. You can not allocate new instances of a java generic type. This can never work:
E hoot = (E) new Object();
Finally, long, short, int, double, and float are not class types; they are primitive types. As such they are not available for use with Java generics.
below method get numbers such as int, float, etc and calculate sum of them.
#SafeVarargs
private static <T extends Number> double sum(T... args) {
double sum = 0d;
for (T t : args) {
sum += t.doubleValue();
}
return sum;
}
Number doesn't support any operations so you need to cast the values to the types required. e.g. If Number is a BigDecimal, there is no += operator.
You should check runtime type (e.g. using instanceof) and cast to the known type and do appropriate addition operation. Not sure what will be type of result, taking in account that the list could contain a lot of different number types.
since the introduction of Java 8 streams and lambda you can have a shorter solution
public interface Adder {
static <E extends Number> E sumValues(Collection<E> objectsToSum, BinaryOperator<E> sumOp) {
return objectsToSum.stream().reduce(sumOp).orElse(null);
}
}
and use it as follows
int sum = Adder.sumValues(List.of(4, 5, 6, 7), Integer::sum);
Note, that Stream::reduce with just accumulator returns Optional that's why I used orElse(null), but I would recommend to send also zero value as parameter to Adder::sumValue
not elegant, but works
public class GenericSum {
public static <T extends Number> Number sum(T x, T y) throws Exception{
// Field
Field primitiveField = x.getClass().getField("TYPE");
// int|float... object
var primitiveType = primitiveField.get(null);
// cast to class
var adder = x.getClass().getMethod("sum", (Class)primitiveType,(Class)primitiveType);
var result = adder.invoke(null,x, y);
return (Number) result;
}
public static void main(String[] args) throws Exception {
var a1 = 3;
var a2 = 5;
var res = sum(a1, a2);
System.out.println(res);
var b1 = 2.0f;
var b2 = 3.0f;
var res2 = sum(b1,b2);
System.out.println(res2);
}
}
I was looking for any implementation of a generic adder accumulator when I came across this question.
I feel this is a lot messy and ugly for most use cases but if you need a very generic one here it is.
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.function.BinaryOperator;
public class Adder implements BinaryOperator<Object> {
#Override
public Object apply(Object partialSum, Object element) {
// if both are instances of Number, then add them
// otherwise we parse the element as string
// and add it to the partial sum
if(partialSum instanceof Number) {
if(element instanceof Number) {
if(partialSum instanceof Integer)
return (Integer) partialSum + ((Number) element).intValue();
if(partialSum instanceof Long)
return (Long) partialSum + ((Number) element).longValue();
if(partialSum instanceof BigInteger)
return ((BigInteger) partialSum).add(BigInteger.valueOf(((Number) element).longValue()));
if(partialSum instanceof Float)
return (Float) partialSum + ((Number) element).floatValue();
if(partialSum instanceof Double)
return (Double) partialSum + ((Number) element).doubleValue();
if(partialSum instanceof BigDecimal)
return ((BigDecimal) partialSum).add(BigDecimal.valueOf(((Number) element).doubleValue()));
else
throw new NumberFormatException("Unknown number type for partialSum: " + partialSum.getClass());
}
else {
if(partialSum instanceof Integer)
return (Integer) partialSum + Integer.parseInt(element.toString());
if(partialSum instanceof Long)
return (Long) partialSum + Long.parseLong(element.toString());
if(partialSum instanceof BigInteger)
return ((BigInteger) partialSum).add(new BigInteger(element.toString()));
if(partialSum instanceof Float)
return (Float) partialSum + Float.parseFloat(element.toString());
if(partialSum instanceof Double)
return (Double) partialSum + Double.parseDouble(element.toString());
if(partialSum instanceof BigDecimal)
return ((BigDecimal) partialSum).add(new BigDecimal(element.toString()));
else
throw new NumberFormatException("Unknown number type for partialSum: " + partialSum.getClass());
}
}
throw new NumberFormatException("partialSum " + partialSum + " must be of type java.lang.Number but found " + partialSum.getClass());
}
}
Honestly this would've been a lot simpler if generic Number types supported the + operator like how Strings does.
The below code doesn't work :
class Stats<T extends Number>
{
T[] nums;
Stats(T[] o)
{
nums = o;
}
double average()
{
double sum = 0.0;
for(int i=0; i < nums.length; i++)
sum += nums[i].doubleValue();
return sum / nums.length;
}
boolean sameAvg(Stats<T> ob)
{
if(average() == ob.average())
return true;
return false;
}
}
class BoundsDemo
{
public static void main(String args[])
{
Integer inums[] = { 1, 2, 3, 4, 5 };
Stats<Integer> iob = new Stats<Integer>(inums);
double v = iob.average();
System.out.println("iob average is " + v);
Double dnums[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
Stats<Double> dob = new Stats<Double>(dnums);
double w = dob.average();
System.out.println("dob average is " + w);
if(iob.sameAvg(dob))
System.out.println("Averages are the same.");
else
System.out.println("Averages differ.");
}
}
But, the following works:
class Gen04<T extends Number>
{
T num;
void set(T a)
{
num = a;
}
T get()
{
return num;
}
boolean equals(Gen04<T> ob)
{
if(num.doubleValue() == ob.get().doubleValue())
return true;
else
return false;
}
}
class GenericCompare
{
public static void main(String args[])
{
Gen04<Integer> obI1 = new Gen04<Integer>();
obI1.set(new Integer(5));
Gen04<Double> obI2 = new Gen04<Double>();
obI2.set(new Double(5.0));
System.out.println("obI1 and obI2 are equal = "+obI1.equals(obI2));
}
}
What is the difference ? In both the programs, I am trying to call a method with parameter type different from the parameter type of the invoking object
In the first snippet, in iob.sameAvg(dob) you attempt to pass a Stats<Double> instance to a method of Stats<Integer>, which expects a Stats<Integer> argument. Since Stats<Double> is not a sub-class of Stats<Integer>, the compiler doesn't accept it.
In the second snippet you call obI1.equals(obI2). equals is a method of Object class that accepts an Object argument, so you can pass any Object instance to it.
EDIT : I see were you got confused. Your second snippet has an equals(Gen04<T> ob) method that overloads Object's equals, but that method is not being called. Instead, the compiler chooses the equals(Object other) method of Object class. If you rename your equals method and call the renamed method from your main, the second snippet would produce the same error.
I have two Java vectors initialized like these:
Integer intArr[] = {100, 200, 300};
Double doubleArr[] = {100.0, 200.0, 300.0};
Vector<Integer> vInt = new Vector<Integer>(Arrays.asList(intArr));
Vector<Double> vDouble = new Vector<Double>(Arrays.asList(doubleArr));
The comparision that I do is like this
boolean equal = vInt.equals(vDouble); //equal = false
How can I compare the two vectors and get true as result considering that, despite the different types, the vectors have the same values?
TIA,
Make the comparison yourself. Note this is subject to conversion errors, for example after around 253 double can no longer represent odd numbers. So I don't recommend comparing long to double, for example.
public static boolean numericEquals(
Collection<? extends Number> c1,
Collection<? extends Number> c2
) {
if(c1.size() != c2.size())
return false;
if(c1.isEmpty())
return true;
Iterator<? extends Number> it1 = c1.iterator();
Iterator<? extends Number> it2 = c2.iterator();
while(it1.hasNext()) {
if(it1.next().doubleValue() != it2.next().doubleValue())
return false;
}
return true;
}
You have no choice but to compare each element in turn; a generic solution would look something like this:
public static boolean compareArrays(List<Integer> vInt, List<Double> vDouble) {
if (vInt.size() != vDouble.size())
return false;
for (int i = 0; i < vInt.size(); i++) {
Integer iVal = vInt.get(i);
Double dVal = vDouble.get(i);
if (!iVal.equals(dVal))
return false;
}
return true;
}
As a side note - you shouldn't be using Vector, unless you really, really need the access to be synchronized, you should use an ArrayList instead.
There is no good way to do this. The values 100.0 and 100 are NOT equal. You will have to subclass Vector and override equals. Inside your equals method, you'll need to adhere to the general contract of equals for Vector, but you'll have to perform some comparison operation like the following:
if(vInt.size() == vDouble.size()){
for(int index = 0; index < vInt.size()){
if(vInt.get(index) - (int) vDouble.get(index) == 0){
//etc.
}
}
}
Note that in this comparison, 100 - (int) 100.4d would evaluate to true.
I think it needs to be iterated and compare like below.
package org.owls.compare;
import java.util.Arrays;
import java.util.Vector;
public class Main {
public static void main(String[] args) {
Integer intArr[] = {100, 200, 300};
Double doubleArr[] = {100.d, 200.0, 300.0};
Vector<Integer> v1 = new Vector<Integer>(Arrays.asList(intArr));
Vector<Double> v2 = new Vector<Double>(Arrays.asList(doubleArr));
boolean isSame = true;
for(int i = 0; i < v1.size(); i++){
int dval = (int)((double)v2.get(i));
if(!v1.get(i).equals(dval)){
isSame = false;
}
}
System.out.println("result >> " + isSame);
}
}
Can anyone help me compare an Integer to a Double using generics?
This is what I have:
public static <T extends Comparable<? super T>> int compare(T arg1, T arg2)
{
return arg1.compareTo(arg2);
}
public static void main(String[] args)
{
Number i = new Integer(5);
Number j = new Double(7);
System.out.println(GenericsTest.compare(i, j));
}
The error message I get is:
Bound mismatch: The generic method compare(T, T) of type GenericsTest is not applicable for the arguments (Number, Number). The inferred type Number is not a valid substitute for the bounded parameter >
The idea of this solution is to widen to BigDecimal and then compare the two numbers (now is cleaner but somehow formatting doesn't work). Note you may reuse this static comparator without having to cast to double anywhere else. In the implementation you do need conversion to double not to lose information, basically you widen to the most general representation.
private static final Comparator<Number> NUMBER_COMPARATOR = new Comparator<Number>() {
private BigDecimal createBigDecimal(Number value) {
BigDecimal result = null;
if (value instanceof Short) {
result = BigDecimal.valueOf(value.shortValue());
} else
if (value instanceof Long) {
result = BigDecimal.valueOf(value.longValue());
} else
if (value instanceof Float) {
result = BigDecimal.valueOf(value.floatValue());
} else
if (value instanceof Double) {
result = BigDecimal.valueOf(value.doubleValue());
} else
if (value instanceof Integer) {
result = BigDecimal.valueOf(value.intValue());
} else {
throw new IllegalArgumentException("unsupported Number subtype: " + value.getClass().getName());
}
assert(result != null);
return result;
}
public int compare(Number o1, Number o2) {
return createBigDecimal(o1).compareTo(createBigDecimal(o2));
};
};
public static void main(String[] args) {
Number i = Integer.valueOf(5);
Number j = Double.valueOf(7);
// -1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(7);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(-7);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Double.MAX_VALUE;
// -1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(Long.MAX_VALUE - 1);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
// sorting Long values
Long[] values = new Long[] {Long.valueOf(10), Long.valueOf(-1), Long.valueOf(4)};
Arrays.sort(values, NUMBER_COMPARATOR);
// [-1, 4, 10]
System.out.println(Arrays.toString(values));
}
As aready said in the comments, Number does not implement Comparable.
But Double and Integer do.
One way to make this work is like this:
public static <T extends Comparable<? super T>> int compare(T arg1, T arg2)
{
return arg1.compareTo(arg2);
}
public static void main(String[] args)
{
Double i = new Integer(5).doubleValue();
Double j = new Double(7);
System.out.println(GenericsTest.compare(i, j));
}
Number doesn't implement Comparable.
Declare both variables as Integer.
private boolean compareObject(Object expected, Object actual) {
if (expected instanceof Number && actual instanceof Number) {
double e = ((Number) expected).doubleValue();
double a = ((Number) actual).doubleValue();
return e == a;
} else {
return com.google.common.base.Objects.equal(expected, actual);
}
}
Create a class that implements Comparable which takes a Number in the constructor.
e.g.
public class GenericNumber implements Comparable<GenericNumber> {
private Number num;
public GenericNumber(Number num) {
this.num = num;
}
// write compare function that compares num member of two
// GenericNumber instances
}
Then simply do this:
GenericNumber i = new GenericNumber(new Integer(5));
GenericNumber j = new GenericNumber(new Double(7));
System.out.println(GenericsTest.compare(i,j));
I am currently working on a lab and would like to know how to handle the following problem which I have spent at least two hours on:
I am asked to create an ArrayList containing the values 1, 2, 3, 4 and 10. Whilst I usually never have any trouble creating an ArrayList with said values, I am having trouble this time. Should I create the ArrayList outside of the method or inside the method? Whichever way I have attempted it, I have been presented with numerous error messages. How do I add values to this ArrayList parameter? I have attempted to add values to it when calling it from the main method, but this still doesn't work. Here is the method in question.
public static double ScalesFitness(ArrayList<Double> weights){
//code emitted for illustration purposes
}
If anybody could help me it would be greatly appreciated. If any more code is required, then please let me know.
Thank you so much.
Mick.
EDIT: The code for the class in question is as follows:
import java.util.*;
public class ScalesSolution
{
private static String scasol;
//Creates a new scales solution based on a string parameter
//The string parameter is checked to see if it contains all zeros and ones
//Otherwise the random binary string generator is used (n = length of parameter)
public ScalesSolution(String s)
{
boolean ok = true;
int n = s.length();
for(int i=0;i<n;++i)
{
char si = s.charAt(i);
if (si != '0' && si != '1') ok = false;
}
if (ok)
{
scasol = s;
}
else
{
scasol = RandomBinaryString(n);
}
}
private static String RandomBinaryString(int n)
{
String s = new String();
for(int i = 0; i > s.length(); i++){
CS2004.UI(0,1);
if(i == 0){
System.out.println(s + "0");
}
else if(i == 0){
System.out.println(s + "1");
}
}
return(s);
}
public ScalesSolution(int n)
{
scasol = RandomBinaryString(n);
}
//This is the fitness function for the Scales problem
//This function returns -1 if the number of weights is less than
//the size of the current solution
public static double scalesFitness(ArrayList<Double> weights)
{
if (scasol.length() > weights.size()) return(-1);
double lhs = 0.0,rhs = 0.0;
double L = 0;
double R = 0;
for(int i = 0; i < scasol.length(); i++){
if(lhs == 0){
L = L + i;
}
else{
R = R + i;
}
}
int n = scasol.length();
return(Math.abs(lhs-rhs));
}
//Display the string without a new line
public void print()
{
System.out.print(scasol);
}
//Display the string with a new line
public void println()
{
print();
System.out.println();
}
}
The other class file that I am using (Lab7) is:
import java.util.ArrayList;
public class Lab7 {
public static void main(String args[])
{
for(int i = 0 ; i < 10; ++i)
{
double x = CS2004.UI(-1, 1);
System.out.println(x);
}
System.out.println();
ScalesSolution s = new ScalesSolution("10101");
s.println();
}
}
you can these
1) use varargs instead of list
public static double scalesFitness(Double...weights)
so you can call this method with :
scalesFitness(1.0, 2.0, 3.0, 4.0, 10.0);
2) create the list outside your method
ArrayList<Double> weights = new ArrayList<Double>();
weights.add(1.0);
weights.add(2.0);
weights.add(3.0);
weights.add(4.0);
weights.add(10.0);
scalesFitness(weights);
Towards your initial posting, this would work:
scalesFitness (new ArrayList<Double> (Arrays.asList (new Double [] {1.0, 2.0, 4.0, 10.0})));
You may explicitly list the values in Array form, but
you have to use 1.0 instead of 1, to indicate doubles
you have to prefix it with new Double [] to make an Array, and an Array not just of doubles
Arrays.asList() creates a form of List, but not an ArrayList, but
fortunately, ArrayList accepts a Collection as initial parameter in its constructor.
So with nearly no boilerplate, you're done. :)
If you can rewrite scalesFitness that would be of course a bit more easy. List<Double> as parameter is already an improvement.
Should I create the ArrayList outside of the method or inside the method?
The ArrayList is a parameter for the method so it need to be created outside the method, before you invoke the method.
You need to import ArrayList in the file that includes your methods. This is probably solved but that's the issue I was encountering.