Please explain sort() and compareTo() - java

I'm writing a code that compares twitter tweets.
Tweet constructor (Tweet class has implement Comparable) (declared inside Tweet.java):
public Treet(String author, String description, Date creationDate) {
mAuthor = author;
mDescription = description;
mCreationDate = creationDate;
}
Say I want to compare two tweets (declared inside Example.java):
Tweet tweetOne = new Tweet("Hello reddit", "josh", new Date(18909042L);
Tweet tweetTwo = new Tweet("Hello again reddit", "Susan", new Date (19419249L);
Then I made an array with these two tweets (declared inside Example.java)
Tweet[] tweets = {tweetOne, tweetTwo]
Then sort (declared inside Example.java)
Arrays.sort(tweets);
Here is my override compareTo() (declared inside Tweet.java)
public int compareTo(Object obj) {
Treet other = (Treet) obj;
if (equals(other)) {
return 0;
}
int dateCmp = mCreationDate.compareTo(other.mCreationDate);
if (dateCmp == 0) {
return mDescription.compareTo(other.mDescription);
}
return dateCmp;
}
A few things really making me bang my head on my desk:
1) how does sortTo() call the compareTo() method, if it does at all?
2) if no1 is true then why is it compareTo(Object obj) instead of compareTo(Tweet twt); seeing as tweets is an array of Tweet class? Presumably:
Array.sort(tweets) -----> compareTo(tweets) ?
3) if (equals(other)) what is equals to what here? Somebody told me that it is if(this.euqals(other)) but again what is this? Is it
tweetOne.equals(other) or tweetTwo.equals(other) or Tweet.equals(other)?
4) mDescription.compareTo(other.mDescription), again what is the mDescription here if
(other.mDescription) == ({tweetOne, tweetTwo}.mDescription)?
if I do this:
int val = mDescription.compareTo(other.mDescription)
What will val be?
I'm especially confused as to what is happening inside the compareTo() method as we want to compare tweetOne AGAINST tweetTwo but there are no evidence of that happening.
I hope someone can guide me through this, this is currently a huge road block for me atm.
Thank you very much in advance.

Java provides two similar mechanisms for comparing two instances for the purpose of ordering; Comparable.compareTo(T) and Comparator.compare(T, T). Both offer three-way comparison (from the linked Wikipedia entry)
Many object-oriented languages have a three-way comparison method, which performs a three-way comparison between the object and another given object. For example, in Java, any class that implements the Comparable interface has a compareTo method which returns a negative integer, zero, or a positive integer.
For an example as to how that can work in practice, consider a generic selectionSort like
static <T extends Comparable<? super T>> void selectionSort(T[] arr) {
int index = 0, i = 0, length = (arr != null) ? arr.length : 0, j;
for (; i < length - 1; index = ++i) {
for (j = i + 1; j < length; ++j) {
if (arr[j].compareTo(arr[index]) < 0) {
index = j; // <-- here we update the index when we find a smaller value
}
}
if (i != index) { // <-- if i == index then it is in the correct position
swap(arr, i, index);
}
}
}
Note that we could also do it with a Comparator;
static <T> void selectionSort(T[] arr, Comparator<T> comp) {
int index = 0, i = 0, length = (arr != null) ? arr.length : 0, j;
for (; i < length - 1; index = ++i) {
for (j = i + 1; j < length; ++j) {
if (comp.compare(arr[j], arr[index]) < 0) {
index = j;
}
}
if (i != index) {
swap(arr, i, index);
}
}
}

compareTo method checks for below things.
a negative integer if anObject < anotherObject
zero if anObject equals anotherObject
a positive integer if anObject > anotherObject
So in your case,
int dateCmp = mCreationDate.compareTo(other.mCreationDate);
if (dateCmp == 0) {
return mDescription.compareTo(other.mDescription);
}
return dateCmp;
}
Here is how it goes,
It first checks for dates, if dates are same, then compares the description.
Tweet will be compared based on description.
This article will definitely help http://www.thejavageek.com/2013/06/17/sorting-user-defined-objects-part-1/

Related

Implementation of min Heap with two parameters for sorting [Java]

I am trying to implement a min heap in java which sorts based on two parameters. Each element of the min heap is an object which contains an int and a string. My current implementation sorts solely based on the integer but I also need it to sort in alphabetical order. For example, if the contents of the objects are as follows:
{ (stopped, 3), (anywhere, 1), (food, 17), (get, 3), (done, 1)}
the output when removing elements from the heap must be:
{(anywhere, 1), (done, 1), (get, 3), (stopped, 3), (food, 17)}
My sink and swim functions are described below:
private void swim(int n){
while (n > 1 && greater(n/2, n)){
exchange(n, n/2);
n = n/2;
}
}
private boolean greater(int i, int j){
return elements[i].getValue() >= elements[j].getValue();
}
private void exchange(int i, int j){
Node tmp = elements[i];
elements[i] = elements[j];
elements[j] = tmp;
}
private void sink(int k){
while(2*k <=n){
int i = 2*k;
if(i < n && greater(i, i+1)) i++;
if(!greater(k,i)) break;
exchange(k,i);
k = i;
}
}
Any help would be greatly appreciated!
Update
Thank you very much to #AlbertoSinigaglia, your solution worked!
you just need to update the greater method in this way:
return /*1*/ elements[i].getValue()>elements[j].getValue
||
/*2*/ (elements[i].getValue()==elements[j].getValue() && elements[i].getString().compareTo(elements[j].getString())>0)
With 1 you check if the int Value is greater, if yes, well ends there, if else it's not, it should be o = or < and we need to take care of the = case, so if the Values are equals, then we compare the String with the compareTo() method, which will return >0 in case the first String is greater than the second string

Sorting an an ArrayList of Objects in Java

I have an object that holds an int value, a String, and a double. Instances of that object are stored in an ArrayList. I want to print that object now but I want to first sort the ArrayList by the String values. I am having a hard time conceptualizing how I'd do that through something like a selection sort. Any help would be grateful!
Here is what I thought you were suppose to do, but that didn't seem to work.
public static void sSortStrings(ArrayList<Student> list) { //Selection sort
int count1;
int count2;
int largest;
String temp;
for (count1 = 0; count1 < list.size() - 1; count1++) {
largest = 0;
for (count2 = largest + 1; count2 < list.size() - count1; count2++) {
if (list[largest].compareTo(list[count2]) < 0) {
largest = count2;
}
}
temp = list[list.size() - 1 - count1];
list[list.size() - 1 - count1] = list[largest];
list[largest] = temp;
}
}
Just to throw in there my professor had included this in the source code, but I'm not sure if I should be calling it instead of the compare to method
public boolean nameComesBefore(Student other) {
return name.compareToIgnoreCase(other.name) < 0;
}
Assuming the Student class has getter for the String property.
Then all you need to do to sort the list is list.sort(Comparator.comparing(Student::getName))
This will sort the given list by student's name.
For more options check javadoc for List.sort() and Comparator.

Writing a generic binary search method

I have written this binary search method that returns the index of the Book object in an ArrayList where the book id matches the inputted book id.
How can I turn this into a generic method that takes a different type of ArrayList of object and search input as params and searches against that input? Is there a way I can generalize it?
public static int bSearch(ArrayList<Book> a, String input)
{
int low = 0;
int high = a.size() - 1;
int index = -1;
while(low <= high)
{
int mid = (low + high) / 2;
if(input.compareTo(a.get(mid).getID()) == 0) //input == target
{
//a binary search that returns index of min or max
index = mid;
return index;
}
else if(input.compareTo(a.get(mid).getID())) < 0) //input < target
high = mid - 1;
else if(input.compareTo(a.get(mid).getID()) > 0) //input > target
low = mid + 1;
}
return index;
}
Do note that you're reinventing the wheel, a generic binary search is already implemented in Collections.binarySearch.
With that in mind, for the sake of an exercise, sure it's possible to transform your implementation to make it generic, with a couple of changes:
Declare type parameter <T>
Make the elements of the input list have type T instead of Book (strictly speaking, ? extends T will be ideal)
Make the type of the element to search for T
Add a comparator parameter, and use it to replace the comparisons on Book::getID
Like this:
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> comparator) {
int low = 0;
int high = list.size() - 1;
int index = 0;
while (low <= high) {
int mid = (low + high) / 2;
int cmp = comparator.compare(key, list.get(mid));
if (cmp == 0) {
index = mid;
return index;
} else if (cmp < 0) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return index;
}
When you use this function to find a Book in a list by ID, you can write the comparator parameter as Comparator.comparing(Book::getID).
(Needless to say, the list parameter must be sorted by book ids already, otherwise binary search won't make sense.)
Lastly, as #nic pointed out in a comment, your implementation has a very undesirable behavior: when an element is not found, it returns 0. This is not so good, for two reasons:
It's impossible to tell if the element was found in the first position of the list, or not found. On a return value of 0, the caller would have to verify if the first element of the list (if exists) is equal to the searched element. That's ugly and painful.
It doesn't give a hint about the position where the missing element could fit in if inserted, which is a very interesting piece of information.
When the element is not found in the list, the common practice is to return -1 -index, where index is the position where the element should be if it was in the sorted list. You can implement this by changing the last line of the method:
return -1 - low;
For your follow-up question, if you wanted this method to take a book id string as the key to search for, then instead of a comparator, the third parameter could be a function that extracts the key from book instances. Then, instead of comparing book instances by a comparator, you could compare the key with the key extracted from instances:
public static <T> int binarySearchByStringField(List<? extends T> list, String key, Function<T, String> keyExtractor) {
int low = 0;
int high = list.size() - 1;
int index = 0;
while (low <= high) {
int mid = (low + high) / 2;
int cmp = key.compareTo(keyExtractor.apply(list.get(mid)));
if (cmp == 0) {
index = mid;
return index;
} else if (cmp < 0) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1 - low;
}

TreeSet in java in replacement of min hip for dijikstra algorithm

Since Java priority queue does not allow to update value of element in priority queue therefore I decided to use TreeSet in Java as an alternate of priority queue to implement Dijikstra shortest distance algorithm. Since I can find element in treeSet with O(log n) than I remove it and now I can insert new element in treeSet. TreeSet.first() always give me a lowest value in treeSet. But this idea is not working. I don't know why?
public class Dijikstra {
public static void dik(int n,int adj[][]) {
TreeSet<nod> p= new TreeSet(new Mycompare());
boolean visit[] = new boolean[n];
nod a[] = new nod[n];
for(int i = 0; i < n; i++) {
a[i] =new nod();
a[i].dis = Integer.MAX_VALUE;
a[i].id = i;
if(i == 0) {
a[i].dis = 0;
}
p.add(a[i]);
}
while(p.isEmpty() == false) {
nod temp = p.first();
p.remove(p.first());
visit[temp.id] = true;
for(int i = 0; i < n; i++) {
if(visit[i] == false && adj[temp.id][i] != 0) {
if(a[i].dis > temp.dis + adj[temp.id][i]) {
p.remove(a[i]);
a[i].dis = temp.dis + adj[temp.id][i];
p.add(a[i]);
}
}
}
}
for(int i = 0; i < n; i++) {
System.out.println(a[i].id+ " " + a[i].dis);
}
}
}
above is my Dijikstra class
my nod class is
class nod {
int dis;
int id;
}
my Mycompare class is
class Mycompare implements Comparator<nod> {
#Override
public int compare(nod t, nod t1) {
return t.dis - t1.dis;
}
}
From the javadoc of TreeSet:
Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal.
The javadoc of Set writes:
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. As implied by its name, this interface models the mathematical set abstraction.
That is, if the comparator returns 0, the element is considered a duplicate, and a set does not admit duplicates. Therefore, a TreeSet is not a priority queue.
after some research i am able to implement treeset which serve as a priority queue
instead of MyCompare class(which is useless) i have to implement compareTo method in class nod and declare treeset without any comparator
TreeSet set = new TreeSet()
class nod implements Comparable{
int dis;
int id;
#Override
public int compareTo(Object o) {
nod right = (nod)o;
if (dis < right.dis) return -1;
if (dis > right.dis) return 1;
if (id < right.id) return -1;
if (id > right.id) return 1;
return 0;
}
}

Looping data structure in Java

Is there an Iterator to loop over data structure in cycles?
Let's say there is an array:
int[] arr = {-1,5,7,-1,-1,-1}
I want to find index of first non -1 value from this array and starting to search from the random position (idx = random.nextInt(arr.length)). For example idx = 4;
So first check if arr[4] == -1, then if arr[5] == -1 and so on. If the end of the array reached then start from 0 position and continue until non -1 found. It is guaranteed that there will be at least one value not equal to -1 in the array.
This can be done so:
int idx = -1;
for (int i = random.nextInt(arr.length); ; i++) {
if (i == arr.length) {
/** start over */
i = 0;
}
if (-1 != arr[i]) {
idx = i;
break;
}
}
Or so:
int idx = -1;
int i = random.nextInt(arr.length);
do {
if (-1 != arr[i]) {
idx = i;
}
i == arr.length ? i=0 : i++;
} while (-1 == idx);
Is there an Iterator, that supports cycling (call next() , if the end of array reached then automatically start from 0)?
Limitations: 1) efficiency is not considered; 2) standard Java API is preferred.
in java API there is no such api which satisfy your problem but you can made it by your own.
what you can do is use List to create LinkedList. to solve your problem.
you can extend List to your class (CircularLinkedList extends List) & then override method hasNext() & getNext() thats all you need.
I don't think there are any iterators that let you know the index of the element as you call next(), so you'd have to keep track of the current index separately. You might be able to build up a "wrap-around" iterator using Guava's Iterators.concat (or some other third-party class) to concatenate an iterator over the trailing part of the array with an iterator over the leading part. However, I think the code is likely to be more complex than a simple for loop or two.
I believe there is no such circular Iterator that will automatically go to the beginning of the array once the end has been reached. I have created one below (not tested, and design is flawed), which requires an entirely new class of code, and is much longer than your short for/while loops.
public class MyCircularIterator<E> implements Iterator<E> {
private List<E> list;
private int pos;
public MyCircularIterator(List<E> list) {
this(list, 0);
}
public MyCircularIterator(List<E> list, int start) {
this.list = list;
pos = start;
}
public boolean hasNext() {
if(list.get(pos) != -1) return false;
return true;
}
public E next() {
if(hasNext()) {
E obj = list.get(pos);
pos = (pos + 1) % list.size();
return obj;
}
}
public void remove() {
list.remove(this.nextIndex);
}
}

Categories

Resources