Suppose I have two classes CLassA and CLassB. And they have one atributte in common, for example the number of elements that each class holds.
How can i create a collection from objects of ClassA and CLassB and sort by that attribute (ascending of descending order, doesn't matter)?
I made a collection of type but when I try to implement the Comparable Interface i can't acess to that method (a get that returns the nr of elements for example).
What solutions do I have?
Thanks for your help!
You could make a custom java.util.Comparator and sort using the Collections.sort(List list,
Comparator c) method.
Really ClassA and ClassB should be related either through an inheritance hierarchy, or by a common interface if you are going to put them both in the same collection.
The simplest thing would be to have a common interface that provides an accessor method for the common attribute. And then the comparator could use that method (through the interface) for fetching the value from ClassA's instance as well as ClassB's instance.
Hmm.. is it possible for ClassA and ClassB to share an interface?
interface InterfaceZ
{
int getCount();
}
class ClassA implements InterfaceZ
{
int getCount() { return _myArray.length; }
}
class ClassB implements InterfaceZ
{
int getCount() { return _complexCollection.size(); }
}
Then just sort the list like so:
List<InterfaceZ> myArray;
... fill up array ...
Collections.sort(myArray, new Comparator<InterfaceZ>() {
public int compare(InterfaceZ o1, InterfaceZ o2) {
return o2.getCount() - o1.getCount();
}});
If you have access to the declaration of CLassA and ~B, then go with a common interface, if not you could write a Wrapper for both Classes:
I defined - against the description - my own classes ~A and ~B, to have something to test. Imagine they're foreign source, and you just have access to the classes.
import java.util.*;
public class SortAB
{
class CLassA {
int [] elements;
public CLassA (int [] a) {elements = a;}
public int getElementCount () {return elements.length;}
}
class CLassB {
List <Integer> elements;
public CLassB (List <Integer> l) {elements = l;}
public int getElementCount () {return elements.size ();}
}
/** a common element-count-wrapper with compareTo method */
abstract class EcWrapper <T> implements Comparable <EcWrapper> {
public abstract int getElementCount ();
public int compareTo (EcWrapper o) {return getElementCount () - o.getElementCount ();}
}
/** concrete Wrapper for CLassA */
class EcAWrapper extends EcWrapper <CLassA> {
private CLassA inner;
public EcAWrapper (CLassA t) {
inner = t;
}
public int getElementCount () {return inner.getElementCount (); }
}
/** concrete Wrapper for CLassB */
class EcBWrapper extends EcWrapper <CLassB> {
private CLassB inner;
public EcBWrapper (CLassB t) {
inner = t;
}
public int getElementCount () {return inner.getElementCount (); }
}
// testing
public SortAB ()
{
int [] ia = {3, 5, 7, 6, 9, 11, 14};
List <Integer> il = new ArrayList <Integer> ();
for (int i: ia)
il.add (i);
il.add (15);
il.add (16);
CLassA a = new CLassA (ia);
CLassB b = new CLassB (il);
List <EcWrapper> list = new ArrayList <EcWrapper> ();
list.add (new EcBWrapper (b));
list.add (new EcAWrapper (a));
show (list);
Collections.sort (list);
show (list);
}
public static void main (String args[])
{
new SortAB ();
}
public static void show (List <EcWrapper> list)
{
for (EcWrapper e: list)
System.out.println ("\t" + e.getElementCount ());
System.out.println ("---");
}
}
Related
I'm trying to create a genetic ArrayList of my class Team but I can't cast Comparable to T despite that T extends Comparable
(I tried extends Comparable without putting < T > and same problem is happening)
public class ArrayList<T extends Comparable>
{
static int MaxSize = 1003;//some random maximum size for our array lists
public int Size = 0;
public int Capacity = 0;
T[] MyList;
public ArrayList()//Default Constructor
{
this(MaxSize);
}
public ArrayList(int Capacity)
{
MyList = (T[]) new Comparable[Capacity]; // Casting
}
}
public class Team implements Comparable<Team>
{
public String Name;
public int Points;
public int GamesCount;
public int Wins;
public int Loses;
public int GoalDifference;//Goals Scored - Goals Against
public int GoalsScored;
public int GoalsAgainst;
public Team(String s)
{
Name = s;
Points = 0;
GamesCount = 0;
Wins = Loses = 0;
GoalDifference = GoalsAgainst = GoalsScored = 0;
}
}
public class Test
{
public static void main(String args[])
{
ArrayList<Team> Teams = new ArrayList<Team>(10);
for(int i = 0 ;i < 10;i++)
{
String TeamName = in.next();
Teams.MyList[i] = new Team(TeamName);//exception here
}
}
}
I am getting the following exception. Many thanks in advance for your help.
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Comparable; cannot be cast to [LTeam;
at Test.main(Test.java:21)
That's obvious, just think about it for a second.
new Comparable[Capacity];
Here you're creating an array which will contain Comparable elements.
Then you're trying to downcast it to an array of Team, which means trying to use a more specific type, and which is not allowed (Upcasting and downcasting in Java), and as you see, throws a ClassCastException.
As your array will contain only types which extends Comparable, you can have a Comparable array inside your ArrayList implementation.
Comparable[] MyList;
Then you can initialize it without casting
MyList = new Comparable[Capacity];
And remember to implement the Comparable#compareTo method in your Team class, otherwise the code won't compile.
You asked for an example.
public class ArrayList<T extends Comparable> {
private static final int MAX_SIZE = 1000;
private final Comparable<T>[] list;
public ArrayList() {
this(MAX_SIZE);
}
public ArrayList(int capacity) {
list = new Comparable[capacity]; // Casting
}
public T get(final int index) {
return (T) list[index];
}
public void set(final int index, final T value) {
list[index] = value;
}
}
Usage is pretty simple
final ArrayList<Team> teamArrayList = new ArrayList<>(3);
teamArrayList.set(0, new Team("One"));
teamArrayList.set(1, new Team("Two"));
teamArrayList.set(2, new Team("Three"));
final String name = teamArrayList.get(0).Name;
As you extended the Comparable<T> interface, you need to implement it
Compares this object with the specified object for order. Returns a
negative integer, zero, or a positive integer as this object is less
than, equal to, or greater than the specified object
A basic example is
#Override
public int compareTo(final Team other) {
return name.compareTo(other.name);
}
In your code, T is Team.
Team IS-A Comparable. Hence, you can cast Team to Comparable.
But every Comparable is not a Team. Therefore, Comparable cannot be cast to Team.
watch this statement: MyList = (T[]) new Comparable[Capacity]; it initializes an array from Comparable interface and put it in to MyList field with type of Team[].
you can test it with:
{
MyList = (T[]) new Comparable[Capacity]; // Casting
System.out.println( MyList.getClass().toString());
}
it writes class [Ljava.lang.Comparable; in output... so in the first attempt to access this field from outside of class you will get ClassCastException even by calling length in test method like this:
public class Test
{
public static void main(String args[])
{
MArrayList<Team> Teams = new MArrayList<Team>(10);
int length = Teams.MyList.length; // this line throws ClassCastException
....
}
}
To solve your problem I suggest change your ArrayList class like this:
public class ArrayList<T extends Comparable<T>>
{
...
Comparable<T>[] MyList;
...
public ArrayList(int Capacity)
{
MyList = new Comparable[Capacity]; // Casting
}
}
How do I create a generic array list in Java that could accept both integers and array?
[123,[],112,[],10]
Both int (Integer wrapper) and array's common base class is Object. So create ArrayList using Object type.
ArrayList<Object> list= new ArrayList<Object>();
But this is not the right way to solve this problem and there is no use of Generics here to make run-time safety. So, re-design your program and allocate each type in seperate list or use any other appropriate Collection type.
Well, the fastest way might be create an auxiliar object that is composed by boths Integers and array letting you to use boths by equal
Create the array list at the Generalization level for all the objects you need in the List. In this case,i.e for int and array, it is java.lang.Object.
Here's a small test I ran:
public static void main(String[] args) {
List<Object> both = new ArrayList<Object>();
both.add(1);
both.add(args);
System.out.println(both);
}
Produces:
[1, [Ljava.lang.String;#1db9742]
As #AbtPst suggested, the most suitable solution would be to have a list of lists. This can be done in many different ways. Personally, I'd create a class with two constructors.
class NumericElement
{
private ArrayList<int> elements;
public NumericElement(int newElement)
{
elements = new ArrayList<int>();
elements.add(newElement);
}
public NumericElement(ArrayList<int> newElements)
{
elements = new ArrayList<int>(newElements); // copying array elements to the new array.
}
public ArrayList<int> getElements()
{
return elements;
}
}
Use a class which has an int and an array as its instance variables. Then create an ArrayList like
import java.util.ArrayList;
public class Hello {
public static void main(String[]args) {
ArrayList<Intarray> myArrayList = new ArrayList<Intarray>();
int[] arr = {3,4,5};
myArrayList.add(new Intarray(2,arr));
}
}
class Intarray {
private int numbers;
private int[] myArray;
public Intarray(int numbers, int[] myArray){
this.numbers = numbers;
this.myArray = myArray;
}
}
You can define a List class with a type-safe interface, hiding an unsafe List<Object> as an internal implementation detail.
This is more work than just using a List<Object> directly. If your list is used only by one class, just use a List<Object>, as an implementation detail of that one class. But if your list is exposed to access by more than just one class, consider using this type-safe approach.
First, define an interface that can represent either an int or a array of ints.
public interface IScalarOrArrayInt { }
And define a sub-interface for each possible element type:
public interface IScalarInt extends IScalarOrArrayInt {
public int getScalarInt();
}
public interface IArrayInt extends IScalarOrArrayInt {
public int[] getIntArray();
}
Then define your list class and its representation. It's interface can be a List<IScalarOrArrayInt>. The representation can be a List<Object>, so that you can put Integer and int[] objects into it directly, without wrapper objects.
public class ListOfScalarsAndArray extends AbstractList<IScalarOrArrayInt> {
private static List<Object> m_list = new ArrayList<Object>();
As noted in the AbstractList documentation, you'll want to define several methods to allow modifying your list. You can delegate them to the internal list, but wrap the return values.
#Override
public void add(int index, IScalarOrArrayInt element) {
m_list.add( index, element );
}
#Override
public IScalarOrArrayInt remove(int index) {
return wrap( m_list.remove( index ));
}
#Override
public IScalarOrArrayInt set(int index, IScalarOrArrayInt element) {
return wrap( m_list.set( index, element ));
}
For the convenience of callers, you can add some methods that accept an unwrapped int or int[]. For example:
public void add( int element ) {
m_list.add( element );
}
public void add( int[] element ) {
m_list.add( element );
}
To satisfy the standard List<> interface, you can wrap return values. Your class controls the internal list, so it alone controls the possible types of list members.
private IScalarOrArrayInt wrap( Object o ) {
if ( o instanceof Integer ) {
final int i = (Integer) o;
return new IScalarInt() {
#Override
public int getScalarInt() {
return i;
}
};
}
else {
assert( o instanceof int[] );
final int[] a = (int[]) o;
return new IArrayInt() {
#Override
public int[] getIntArray() {
return a;
}
};
}
}
I am trying to sort a list of type A named BinOrder in class B according to Class A's int r.
However i am receiving this error for the line Collections.sort(BinOrder);
The method sort(List<T>) in the type Collections is not applicable for the arguments (ArrayList<A>)
Class A:
public class A{
int s;
int r;
public A(int si, int ri) {
s=si;
r= ri;
}
}
Class B:
import java.util.ArrayList;
import java.util.Collections;
public class B implements Comparable<A> {
public Iterator<A> randomMethodName(int a) {
ArrayList<A> BinOrder = new ArrayList<A>();
A a = new A(1,3)
A a2 = new A(1,4)
BinOrder.add(a);
BinOrder.add(a2);
}
// sort array in increasing order of r
Collections.sort(BinOrder);
return BinOrder;
}
#Override
public int compareTo(A list) {
return null;
}
}
To be able to use the single-argument version of Collection.sort() on an ArrayList of A, A should implement the Comparable interface:
public class A implements Comparable<A> {
...
#Override
int compareTo(A rhs) {
...
}
}
Here's the signature of Collections.sort :
public static <T extends Comparable<? super T>> void sort(List<T> list)
A must implement Comparable for this method.
You try to pass BinOrder to this method, when BinOrder is of type ArrayList<A>, but since A does not implement Comparable<A>, it doesn't fit the signature of the method.
Either change A to implement Comparable, or use the sort method that accepts a Comparator :
public static <T> void sort(List<T> list, Comparator<? super T> c)
I have written a class A such as following
class A <E> { // class A has objects of E
int x;
private B<T> next // a object of inner class
class B<T> {
// an inner class having objects of type T
T[] elements = (T[]) Object[x];
// has other stuff including many objects
}
public A<E> func ( B<E> val ){
Here I want to clone the value of val so that I can do different operations on other
}
The problem comes that I wish to write B<E> Temp = B<E>Value.clone() where Value is defined in the code.
but it says that clone is not visible.
What should I do to make it so....
Thanks a lot...
clone() is protected so you just need to redefine in B to do whatever you need.
Here an example to the answers from Peter (not tested, may need some syntax checks):
class A <E> { // class A has objects of E
int x;
private B<T> next // a object of inner class
class B<T> implements Cloneable {
public B<T> clone() {
try {
B<T> klon = (B<T>) super.clone();
// TODO: maybe clone the array too?
return klon;
}
catch(CloneNotSupportedException) {
// should not occur
throw new Error("programmer is stupid");
}
}
// an inner class having objects of type T
T[] elements = (T[]) Object[x];
// has other stuff including many objects
}
public A<E> func ( B<E> val ){
B<E> clone = val.clone();
// more code
}
It's better to not use clone() but to implement a copy constructor on B:
class B extends A {
// an inner class having objects of type
List<String> strings = ArrayList<String>();
public B(B that) {
super(that); // call the superclass's copy constructor
this.strings = new ArrayList<String>();
this.strings.add(that.strings);
}
// ...
}
then call
public C func ( B val ){
B clone = new B(val);
}
(removed the generics stuff to limit demonstration on the copy constructor itself)
Consider this code:
import java.util.*;
class jm45 implements Comparator<jm45>
{
private int x;
jm45(int input) { x = input; }
public static void main( String args[] )
{
List list = new ArrayList();
list.add(new jm45(2));
list.add(new jm45(2));
Collections.sort(list); //faulty line
}
public int compare( jm45 t1 , jm45 t2 )
{
return t1.x - t2.x;
}
}
Your class implements Comparator<jm45> instead of Comparable<jm45>.
A Comparator knows how to compare two objects - a Comparable knows how to compare another with itself.
You either need to pass in a comparator for sort() to use (as the second argument) or the values have to be comparable.
Here's a version which uses the Comparable interface instead:
import java.util.*;
class Test implements Comparable<Test>
{
private int x;
Test(int input)
{
x = input;
}
public static void main(String args[])
{
List<Test> list = new ArrayList<Test>();
list.add(new Test(2));
list.add(new Test(2));
Collections.sort(list);
}
public int compareTo(Test other)
{
return x - other.x;
}
}
And here's a version which uses the Comparator interface:
import java.util.*;
class TestComparator implements Comparator<Test>
{
public int compare(Test t1, Test t2)
{
return t1.getX() - t2.getX();
}
}
class Test
{
private int x;
Test(int input)
{
x = input;
}
int getX()
{
return x;
}
public static void main(String args[])
{
List<Test> list = new ArrayList<Test>();
list.add(new Test(2));
list.add(new Test(2));
Collections.sort(list, new TestComparator());
}
}
There's nothing to stop a class implementing Comparator<T> for itself, but it's a little strange for it to do so. For instance, you wouldn't normally ask one string to compare two other ones with each other - it's got nothing to do with the original string itself.
From the Collections.sort javaDoc:
Sorts the specified list into ascending order, according to the
natural ordering of its elements. All elements in the list must
implement the Comparable interface. Furthermore, all elements
in the list must be mutually comparable (that is,
e1.compareTo(e2) must not throw a ClassCastException
for any elements e1 and e2 in the list).
Your class implements Comparator, not Comparable.