ArrayList Generic Sorter - java

I want to pass in an arraylist and sort it no matter whats in it
Error I am getting: Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Character
ArrayList myArray = new ArrayList();
myArray.add("wayne");
myArray.add("bob");
myArray.add('h');
myArray.add(4);
myArray.add(5.50);
ArrayList sortedArray = Validate.Sort(myArray);
for(Object x: sortedArray)
{
System.out.println(x);
}
public static ArrayList Sort(ArrayList value)
{
Collections.sort(value);
return value;
}

Your ArrayList has a mix of String and char values. So when the two try to get compared, the String's compareTo method is being called. It has a signature of compareTo(String,String), so it's trying to cast the char to a String. Either put all Strings in, or write a custom comparator that handles mixed types like this.

Take a look at Comparator:
http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html
In your case the compareTo() may look like:
public int compareTo(Object a, Object b){
if(a == b)
return 0;
if(a==null)
return 1;
if(b==null)
return -1;
return a.toString().compareTo(b.toString);
}
But I think this would be kind of useless.

I want to pass in an arraylist and sort it no matter whats in it
What is this supposed to mean? A total ordering is a binary relation which satisfies some properties (antisimmetry, transitivity, totality). More easily, given two elements, you must identify a criterion to determine which is smaller/bigger than the other.
You cannot do this, unless you know what these elements actually are. If you want to sort an array of whatever, given object A and B, whose types you don't even know, how can you tell which is bigger than the other?
In Java, you might use the hashCode, which is indeed a criterion, but it's hardly useful. If you want to avoid duplicates, you can use a Set rather than a List. Anyway, if you really want to sort elements based on their hashCode, you can do it like this:
private static final Comparator<Object> hashComparator
= new Comparator<Object>() {
#Override
public int compare(Object a, Object b) {
return System.identityHashCode(a) - System.identityHashCode(b);
}
#Override
public boolean equals(Object obj) {
//this is a static singleton, nothing can be equal to it
return false;
}
};
public static ArrayList Sort(ArrayList value)
{
Collections.sort(value, hashComparator);
return value;
}
EDIT: if you are interested in sorting a list of just Strings and Characters (or if you want to sort items based on their string representation) the right thing to do is probably convert everything to strings, or use a SortedMap<String, Object>. Otherwise, you can do the same I just showed you before, but using a more specific compare function, such as:
public int compare(Object a, Object b) {
return a.toString().compareTo(b.toString());
}

Related

compareTo sets 10 before 2 when sorting on value

Let me give you an example for what i'm trying to achieve. Look only to the numbers because it's a card game.
I have:
harten5 klaveren4 klaveren7 schoppen5 ruiten5 schoppen2 klaverenheer schoppenheer schoppendame schoppen6 klaverenboer schoppen8 ruitenheer klaveren6...
I want to sort this on the value to:
schoppen2 harten2 ruiten2 klaveren2 ruiten3 harten3 schoppen3 klaveren3 klaveren4 harten4 schoppen4 ruiten4 harten5 schoppen5 ruiten5...
But i get the 10 before the 2 like this:
schoppen10 ruiten10 harten10 klaveren10 schoppen2 harten2 ruiten2 klaveren2 ruiten3 harten3 schoppen3 klaveren3...
This is my basic compareTo Method:
#Override
public int compareTo(Card p) {
return this.value.compareTo(p.value);
}
Because String's (I guess this.value is String) compareTo compares lexicographically, whilst you want numerically. So you have to reimplement it, take substring (or find the last part which is a digit, convert it to Integer and then user compareTo on that Integer.
In general, I think your class Card could be improved a bit. In particular, I would rewrite it:
class Card {
private String value;
private Integer rank;
...
public int compareTo(Card c) {
// Additional logic if you need to consider
// also value (suite) in comparison
return this.rank.compareTo(c.rank);
}
}
But you can also use an enum for this purpose.
String java API compareTo
I'm guessing you want the reverse order? If so, then just change your implementation to this:
#Override
public int compareTo(Card p) {
return p.value.compareTo(this.value);
}
It really depends on what the type of "value" is and how the "compareTo" is implemented. Alternatively, you could just do this if "value" is an integer:
#Override
public int compareTo(Card p) {
return this.value - p.value;
}
I believe your value is stored as an String. If you do not want to change the data type of value, you can implement the compareTo method in the following way:
public int compareTo(Card p) {
return Integer.parseInt(this.value).compareTo(Integer.parseInt(p.value));
}

What type to return?

Consider a method which produces different types of results. In my case it's either an ArrayList or an Integer (pseudo code):
int a = ... // value for a comes from another function
public ArrayList compute(){ // return either ArrayList or Integer
if(a==1){
ArrayList result = new Arraylist()
for(int i=0; i<=something; i++){
arr.add(...);
}
}
if(a==2){
int result;
result = somethingElse;
}
return result;
}
Depending on the result of a, the result of result comes either from a loop and loads the results into an ArrayList, or in the second case it will just be a single number.
What type should the method return?
Return a List<Integer>. For a single integer simply return a list with a single element.
An alternative to returning a List (but "functionally" the same),
public void compute(List<Integer> result){
// add/remove/set the given list,
}
And although this looks like a bad design in general, you may in this case actually return a value that indicates if a "list" or a single value (a list with one element) is returned.
public boolean compute(List<Integer> result){ ...
Or, better, the length of the list (depends on what you're really trying to achieve):
public int compute(List<Integer> result){
...
return result.size();
}
You can change the signature of the method to be public Object compute(), so that you can return both ArrayLists and Integers, but I'm not exactly sure why you'd want to do this.
It just means that whenever you call compute(), you're going to need to check the type of the Object that you received, e.g.
Object result = compute();
if(result instanceof ArrayList) {
// Do ArrayList stuff
} elseif(result instanceof Integer) {
// Do Integer stuff
}
Note: Object is the super class for all objects in Java, so if there is a time where you may want to return lots of different things, you can use Object. But the better solution may be to create an Interface, if the things you're returning will have something in common.
See here: http://docs.oracle.com/javase/tutorial/java/concepts/interface.html

How to create an equals method that compares two object arrays of a class?

I am trying to create a equals method that compares two objects. The thing is, I'm a bit a of new to this stuff so I'll try to explain my goal as easy as possible.
public class A {
...
}
public class B {
private A[] arr = new A[10];
public boolean equals(A[] temp) {
//compare
}
}
Assume the code above is a summary of what I have. Now, assume I had: arr.equals(Obj)
Obj being another A[] object. Now in my equals statement, I want to reference the original arr array, how do I go about doing that?
For example, let's say I wanted to compare arr's length to temp's length (aka Obj's length), how would I do that? I know it would be something like (temp.length == arr.length) but how do I access arr when I pass it through by doing arr.equals(obj)?
EDIT: Just to clarify, assume the objects aren't simple arrays. So for instance, class A could have a Name, a Type (Both Strings) and possibly a Quantity (an int), so I wouldn't be able to simply compare them like they're two normal arrays.
Thanks!
You can use java.util.Arrays.equals(Object[] a, Object[] a2) which tests if the two specified arrays of Objects are equal to one another
Use the keyword this, which always represents the object you are applying the method to (immediately before the dot). For example:
public boolean equals(A[] temp) {
return this.length == temp.length ;
}
Now, in the particular case of your code, you are not defining method equals as part of class A, but of a class B whose instances contain arr. Then, the solution would be:
public boolean equals(A[] temp) {
return this.arr.length == temp.length ;
}
Write a equals mwthod in your class A
public class A {
...
//Override equals method.
}
Now if you want to compare 2 arrays of class A you can simply use java.utils.Arrays.equals(A a1[], A a2[]);
You have to override equals method in class A coz java.utils.Arrays.equals internally uses class A's equals.
Here is an example, go through it.

setting hashcode and equals to create a set with unique object

I would create a Set exactly HashSet to contains only char.for example a,b,c,d,e,f,g...
but these chars are not represented by the primitive type but I have an object
public FirstChar{
private char c;
public FirstChar(char c){
this.c = c;
}
}
Now i want to add the object FirstChar into a set but to avoid repeated elements I have to implement HashCode() and equals()
I know how to implement equals but how can i implement hashcode in the way I could have only one element in the set?
NB. Please don't say me to use Eclipse
EDIT: I've just read your comment that you only want one letter in the entire set - which sounds like a very odd requirement, but it's basically fulfilled by something like:
public final class FirstChar {
private final char c;
public FirstChar(char c) {
this.c = c;
}
#Override public int hashCode() {
return 0;
}
#Override public boolean equals(Object other) {
return other instanceof FirstChar;
}
}
In other words, every instance of FirstChar is deemed equal to every other instance, and they all have the same hash code. As I say, this is really strange... is it definitely what you want?
Original answer
Implementing hashCode() for a value which only logically has a single character is easy:
#Override
public int hashCode() {
return c; // Use implicit conversion to int
}
Check against the contract of Object.hashCode and you'll find this works fine - assuming your equals method basically just compares values of c. (It's not clear what you meant when you wrote "in the way I could have only one element in the set" - I assume you mean only one element per distinct character.)
However, I'm confused as to what value your FirstChar class provides over just using java.lang.Character. Is there any reason you can't just use a Set<Character>?
In any case, from what I can tell, the hashCode method in the Character class simply returns the char as an int.
In your specific case, if you want the set to only contain the first FirstChar added to it, you can make all FirstChars equal to each other:
class FirstChar{
private char c;
public FirstChar(char c){
this.c=c;
}
public String toString(){
return String.valueOf(c);
}
public boolean equals(Object o){
return o instanceof FirstChar;
}
public int hashCode(){
return 42;
}
}
But unless you have a very good reason, this doesn't sound like a good idea.

Anything wrong about my Intset Class?

I design new IntSet Class that use ArrayList. first, i extends Intset by ArrayList and i start implement method. i face some problem in my union() method. here is my code...
public class IntSet extends ArrayList<Integer>{
private static final long serialVersionUID = 1L;
private ArrayList<Integer> intset;
public IntSet(){
this.intset = new ArrayList<Integer>();
}
public IntSet(ArrayList<Integer> intset){
this.intset = intset;
}
public void insert(int x){
this.intset.add(x);
}
#Override
public Integer remove(int x){
int index = intset.indexOf(x);
this.intset.remove(index);
return 1;
}
#Override
public int size(){
return this.intset.size();
}
#Override
public Integer get(int index){
return this.intset.get(index);
}
public boolean member(int x){
if(intset.indexOf(x)==-1) return false;
else return true;
}
public IntSet union(IntSet a){
IntSet intersectSet = new IntSet();
intersectSet.insert(0);
intersectSet.insert(1);
System.out.println(intersectSet.size());
System.out.println(intersectSet.contains(1));
for(int i=0; i<a.size(); i++){
}
return intersectSet;
}
public String toString(){
if(intset.size()==0) return "[]";
String s = "[" + intset.get(0).toString();
for(int i=1; i<intset.size(); i++){
s += "," + intset.get(i).toString();
}
return s += "]";
}
}
In method
union(IntSet a);
I constract new Intset object then add 2 value (0, 1) into intersectSet variable.
intersectSet.insert(0);
intersectSet.insert(1);
then i print size of intersectSet it shown me 2 that is correct!
but when i need to check that there is 1 in intersectSet or not? it shown me false.
System.out.println(intersectSet.contains(1));
In fact it should show me true because in intersectSet have integer 1.
anything wrong about my code and should i extends ArrayList for IntSet class?
Some suggestions on the class design:
Don't have your class extend ArrayList. A "set" really shouldn't be extending List. However, you should probably implement Set. This will have the added bonus of the compiler telling you what methods you need to implement for a set.....
For fastest performance (but more work!), you may want to use an internal array rather than an ArrayList.
Consider making the structure immutable, with functions that return a new copy rather than mutating the set in place. Depending on your usage, this may be a better solution, especially if you are mostly dealing with small, non-changing sets.
Again depending on your usage, you may want to override hashCode and equals to implement value based equality
When you construct the Intset with an ArrayList, you should ideally defensively copy (clone) the ArrayList. You don't want you set to change if someone mutates the original ArrayList.
The problem here is that you actually have 2 ArrayLists. The IntSet class IS A ArrayList, but this class contains a second ArrayList intset. Get rid of one of these ArrayLists. To demonstrate this add this second line:
System.out.println(intersectSet.contains(1));
System.out.println(intersectSet.intset.contains(1));
this will output:
false
true
So you are going to have to make a choice, do I inherit from ArrayList or do I contain an ArrayList. Of course what I am getting at here is Item 16 from Effective Java, Favor composition over inheritance.
You are both extending ArrayList and managing your own internal ArrayList object, this means that for all the methods which you have overridden you are interacting with your intset member variable, otherwise you are interacting with the inherited internal representation used by the ArrayList superclass. If you override the contains method you will get the correct behaviour.
I suggest that you drop the subclassing of ArrayList and instead implement the List or Set interfaces, although this depends on the exact problem you've been asked to solve.
you need to override contains method.
public boolean contains(Object o) {
return intset.contains(o);
}
and the rest of ArrayList methods that related to its elements.
and i doesn't seems to me a good solution. you may try better approach.

Categories