I am facing an issue while sorting List<List<Object>>. I have created a Custom Comparator where i have written the code to sort the data.
public class CustomComparator implements Comparator<List<Object>>
{
static int i = 0;
public int compare(List<Object> o1, List<Object> o2) {
if (i < o1.size()) {
System.out.println(i);
Object obj1 = o1.get(i);
Object obj2 = o2.get(i);
if (obj1 != null && obj2 != null) {
int value = compareTo(obj1.toString(), obj2.toString());
if (value == 0) {
i++;
compare(o1, o2);
}
return value;
}
if (obj1 == null && obj2 != null) {
return -1;
}
if (obj1 != null && obj2 == null) {
return 1;
}
if (obj1 == null && obj2 == null) {
i++;
compare(o1, o2);
}
}
else{
i=0;
}
return 0;
}
public int compareTo(String value1, String value2) {
return value1.compareTo(value2);
}
}
Logic that i am trying to implement is that first it will try to sort the using the Object at 0th position. If the values at 0th position is equal or null then it will sort using the Object at 2nd position.etc.
If either of the values are null then that element will be shifted downward.
However when i try to sort using the code that I have written it gets sort but neither in ascending or descending order. It is just shuffled.
It makes no sense to use recursion here. Just iterate over the two Lists in a loop to compare their elements.
Your recursive implementation doesn't work since you ignore that value returned by the recursive calls. The use of a static variable for keeping the index is also a bad idea. What will happen if your Comparator instance is used by two threads concurrently?
Try this,
public int compare(List<Object> o1, List<Object> o2) {
public int compare(List<Object> o1, List<Object> o2) {
int i=0;
//TODO validation here for null check
while(i< o1.size()){
Object obj1 = o1.get(i);
Object obj2 = o2.get(i);
if (obj1 == null && obj2 != null) {
return -1;
}else if (obj1 != null && obj2 == null) {
return 1;
}else if(obj1 != null && obj2 != null){
int value = compareTo(obj1.toString(), obj2.toString());
if(value!=0){
return value;
}
}
i++;
}
return 0;
}
}
public static void main(String args[]) {
List<List<String>> list = new ArrayList<>();
List<String> a = new ArrayList<>();
a.add("c");
a.add("a");
List<String> b = new ArrayList<>();
b.add("h");
b.add("b");
list.add(a);
list.add(b);
Collections.sort(list,new Comparator<List<String>>() {
#Override
public int compare(List<String> o1, List<String> o2) {
Collections.sort(o1);
Collections.sort(o2);
//Compare your list based on your criteria
}
});
}
Related
I am trying to check whether my levelorder of my Binary Search Tree is equal to the other one. To do this, I tried to make a compareTo method. I only give equal values to the method, but it keeps on saying the condition is false. When I place breakpoints, I see that the values are still equal. I am probably not understanding it correctly. Does anyone know how to solve this?
Here is what I did, as you can see below, the compareTo returns a 1 instead of a 0:
import edu.princeton.cs.algs4.BST;
import java.util.*;
public class MyBST implements Comparable<MyBST>{
private Object e;
public MyBST(Object e){
this.e = e;
}
private Object getE(){
return e;
}
public static void main(String[] args) {
int size = 4;
Random r = new Random();
Set<Integer> tes = new LinkedHashSet<>(size);
Stack<Integer> stack = new Stack<>();
while (tes.size() < size) {
tes.add(r.nextInt(10));
}
System.out.println("possible combinations");
Set<Stack<Integer>> combos = combos(tes, stack, tes.size());
Object[] arr = combos.toArray();
List<String> d = new ArrayList<>();
for (Object s : arr) {
String b = s.toString();
b = b.replaceAll("\\[", "").replaceAll("\\]", "");
d.add(b);
}
int index = 0;
do {
BST<String, Integer> bst1 = new BST<String, Integer>();
BST<String, Integer> bst2 = new BST<String, Integer>();
String key1 = d.get(index);
String key2 = d.get(index);
key1 = key1.replaceAll(" ", "");
String[] m = key1.split(",");
key2 = key2.replaceAll(" ", "");
String[] n = key2.split(",");
System.out.println("1e order");
for (int j = 0; j < m.length; j++) {
System.out.println(m[j]);
bst1.put(m[j], 0);
}
System.out.println("2e order");
for (int j = 0; j < n.length; j++) {
System.out.println(n[j]);
bst2.put(n[j], 0);
}
System.out.println("levelorder 1e BST");
MyBST e = new MyBST(bst1.levelOrder());
MyBST y = new MyBST(bst2.levelOrder());
System.out.println(bst1.levelOrder());
System.out.println("levelorder 2e BST");
System.out.println(bst2.levelOrder());
System.out.println(e.compareTo(y) + "\n");
index++;
} while (index < arr.length - 1);
}
public static Set<Stack<Integer>> combos(Set<Integer> items, Stack<Integer> stack, int size) {
Set<Stack<Integer>> set = new HashSet<>();
if (stack.size() == size) {
set.add((Stack) stack.clone());
}
Integer[] itemz = items.toArray(new Integer[0]);
for (Integer i : itemz) {
stack.push(i);
items.remove(i);
set.addAll(combos(items, stack, size));
items.add(stack.pop());
}
return set;
}
#Override
public int compareTo(MyBST o) {
if (this.e == o.e) {
return 0;
}
else
return 1;
}
}
Here you can find the BST.java class: BST.java
And the output is something like:
The breakpoint at the compareTo method says:
When you're using the == operator you're actually checking to see if the references point to the same object in memory. From your debugging screenshot you can see that they are not. this.e points to object Queue#817 while o.e points to Queue#819.
If all you want to do is test for equality, then just override equals and hashCode. You can do it like this (rest of class omitted):
public class MyBST {
private Object e;
public MyBST(Object e) {
this.e = e;
}
public Object getE(){
return e;
}
#Override
public int hashCode() {
return Objects.hashCode(e);
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof MyBST))
return false;
MyBST me = (MyBST) obj;
if (e == null) {
if (me.e != null)
return false;
} else if (!e.equals(me.e))
return false;
return true;
}
}
Implementing Comparable is more involved since you need to check for less, equal, or greater than other instances of MyBST. Unfortunately, the only field in MyBST is an Object which does not tell you anything about its actual fields. So without specific fields with which to test you need to ensure that the Object you pass also implements Comparable. Then you can declare your class like this. Rest of class omitted.
It simply says that
MyBST is comparable.
And the object that is passed in the constructor is comparable.
class MyBST<T extends Comparable<? super T>> implements Comparable<MyBST<T>>{
private T e;
public MyBST(T e){
this.e = e;
}
public T getE(){
return e;
}
#Override
public int compareTo(MyBST<T> o) {
return e.compareTo(o.e);
}
}
The other alternative is to simply pass the actual object type and store it as such, not as Object. Then just implement Comparable in MyBST and use the appropriate fields of the passed object. Lets say the object was an Apple object, you could do this.
class Apple {
String type;
int weight;
}
class MyBST implements Comparable<MyBST> {
private Apple apple;
public MyBST(Apple apple) {
this.apple = apple;
}
#Override
public int compareTo(MyBST e) {
// this could be different depending on how you wanted
// to compare one apple to another. This comparison favors
// type over weight.
// check type - String class implements comparable
int ret = apple.type.compareTo(e.apple.type);
if (ret != 0) {
return ret;
}
// same type so check weight
if (apple.weight < e.apple.weight) {
return -1;
}
if (apple.weight > e.apple.weight) {
return 1;
}
return 0; // equals apples based on criteria
}
}
Finally, you have this.
private Object getE(){
return e;
}
A private getter is not usually very useful. Make it public.
I don't know why find() method does not work for some numbers. Here is the code.
I'm talking about finding element in Double Linked List.
public DLLNode<E> find(E o) {
if (first != null) {
DLLNode<E> tmp = first;
while (tmp.element != o && tmp.succ != null)
tmp = tmp.succ;
if (tmp.element == o) {
return tmp;
} else {
System.out.println("Element does not exist in a list");
}
} else {
System.out.println("List is empty");
}
return first;
}
Most likely, your issue is with :
if (tmp.element == o) {
return tmp;
}
which is comparing objects using reference equality, not value equality. You want to use .equals for that. You mention it works for some numbers, which I'm guessing means you have a DLLNode<Integer> in your test - you're probably just running into the fact that the JVM caches a small subset of Integer objects (I think between -127 and +128) so those appear to work when using ==.
You need to use equals instead of ==
== compares references, ex:
new Double( 2d ) == new Double( 2d ) will be false,
but new Double( 2d ).equals(new Double( 2d )) will be true.
public DLLNode<E> find(E o) {
if (first != null) {
DLLNode<E> tmp = first;
while (!tmp.element.equals(o) && tmp.succ != null)
tmp = tmp.succ;
if (tmp.element.equals(o)) {
return tmp;
} else {
System.out.println("Element does not exist in a list");
}
} else {
System.out.println("List is empty");
}
return first;
}
Is the statement list.contains("are") (have commented it) being checked by matching character to character ?
import java.util.*;
class Tester {
public static void main(String args[]) {
String arr[] = {"how","are","you","veena"};
LinkedList<String> list = new LinkedList<String>();
for(String s : arr) {
list.add(s);
}
if(list.contains("are")) { // STATEMENT
System.out.println("Found !");
}
}
}
In this program if statement works. How does the contain method work ?
That method iterates over the linked list, and compare each element with the element passed by invoking equals() method. In this case, it will invoke String#equals(Object) method.
this is implementations of method contains and indexOf from LinkedList
public boolean contains(Object o) {
return indexOf(o) != -1;
}
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
so as you see it is iterating trough array till it finds first matching element
Ok, I got a Table with a list of No.
No
1
2
5
10
20
If i set columnSortHandler for the No column using String like this:
columnSortHandler.setComparator(noColumn, new Comparator<String[]>() {
#Override
public int compare(String[] o1, String[] o2) {
if (o1==o2) {
return 0;
}
if (o1 != null) {
return (o2 != null) ? o1[0].compareTo(o2[0]) : 1;
}
return -1;
}
});
Then it won't sort like integer but like String. Ex: it will sort like this:
No
1
10
2
20
5
Then it is not correct.
So tried:
columnSortHandler.setComparator(noColumn, new Comparator<String[]>() {
#Override
public int compare(String[] o1, String[] o2) {
if (o1==o2) {
return 0;
}
if (o1 != null) {
return (o2 != null) ? Integer.parseInt(o1[0]).compareTo(Integer.parseInt(o2[0]) : 1;
}
return -1;
}
});
But compareTo does not apply for Integer.
So my question is
How to #Override Comparator to make the Column in CellTable sort based on Integer not based on String (GWT)?
Use Integer.valueOf() as shown below
return (o2 != null) ? Integer.valueOf(o1[0]).compareTo(Integer.valueOf(o2[0])) : 1;
instead of
return (o2 != null) ? Integer.parseInt(o1[0]).compareTo(Integer.parseInt(o2[0]) : 1;
Integer.parseInt() returns primitive int not wrapper Integer class.
Cannot invoke compareTo(int) on the primitive type int
There are lots of ways to convert Stringinto Integer wrapper class.
Try any one:
Integer.valueOf(String)
new Integer(String)
Integer.getInteger(String)
I have defined a simple private class named SetOb which contains an int and a Set data structure. I have a HashMap in the 'main' method with SetOb as Key and Integer as value. Now as you can see in the main method, when I feed the HashMap with a SetOb instance and then look for an instance with exactly the same value, it returns 'null'. This has happened with me quite a few times before when I use my own defined data structures like SetOb as Key in HashMap. Can someone please point me what am I missing ?
Please note that in the constructor of SetOb class, I copy the Set passed as argument.
public class Solution {
public static Solution sample = new Solution();
private class SetOb {
public int last;
public Set<Integer> st;
public SetOb(int l , Set<Integer> si ){
last = l;
st = new HashSet<Integer>(si);
}
}
public static void main(String[] args) {
Map<SetOb, Integer> m = new HashMap< SetOb, Integer>();
Set<Integer> a = new HashSet<Integer>();
for(int i =0; i<10; i++){
a.add(i);
}
SetOb x = sample.new SetOb(100, a);
SetOb y = sample.new SetOb(100, a);
m.put(x,500);
Integer val = m.get(y);
if(val!= null) System.out.println("Success: " + val);
else System.out.println("Failure");
}
}
Your x and y are not the same object instances hence contains is not able to match y against x, which ends up not finding the matching key/value in the Map.
If you want the match to succeed, please implement(override) hasCode & equals method in SetOb which will compare the field values.
Sample methods(Eclipse generated) as below:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + last;
result = prime * result + ((st == null) ? 0 : st.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SetOb other = (SetOb) obj;
if (last != other.last)
return false;
if (st == null) {
if (other.st != null)
return false;
} else if (!st.equals(other.st))
return false;
return true;
}
The default implementation of hashCode uses object identity to determine the hash code. You will need to implement hashCode (and equals) in your private class if you want value identity. For instance:
private class SetOb {
public int last;
public Set<Integer> st;
public SetOb(int l , Set<Integer> si ){
last = l;
st = new HashSet<Integer>(si);
}
#Override
public boolean equals(Object other) {
if (other.class == SetOb.class) {
SetOb otherSetOb = (SetOb) other;
return otherSetOb.last == last && otherSetOb.st.equals(st);
}
return false;
}
#Override
public int hashCode() {
return 37 * last + st.hashCode();
}
}
SetOb needs to override the hashCode() and thus the equals() methods.
Hash-based collections use these methods to store (hashCode()) and retrieve (hashCode()) and equals()) your objects.