Collections.Sort an ArrayList in java - java

I use this function in java:
Collections.sort(an Arraylist, new CustomComparator);
The compare method in CustomComparator class will return an int. What this means to the sort procedure? what's the number of this value and how will affect the sorting procedure?
More specifically i want in compare method to compare two values. Here is my code:
import java.util.Comparator;
public abstract class CustomComparator implements Comparator<HLine> {
#Override
public int compare(HLine hl1, HLine hl2) {
return hl1.y < hl2.y;
}
}
and i call for sorting:
Collections.sort(hlines, new comparator());
hlines is an Arraylist of a object's with a Point and two doubles. I want to compare the second double in two object's.

Basically, as stated in the Javadoc of Comparator.compare and Comparable.compareTo these methods return
a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
Meaning that if you call
new Integer(1).compareTo(0)
it will return a negative integer, which indicates, that 0 has to be ordered before 1.
new Integer(1).compareTo(1)
it will return 0, which indicates, that both values has to be ordered on the same level.
new Integer(1).compareTo(2)
it will return a positive integer, which indicates, that 2 has to be ordered after 1.
To fix your codesample, you need to rewrite compare() so it will return an Integer, as it is now it returns a boolean and will not compile.
Because you are trying to compare doubles you can simply change to
#Override
public int compare(HLine hl1, HLine hl2) {
return hl1.y - hl2.y;
}

sort() method sort the elements but first they are compared.For the comparison purpose, sort() method can use compare() or compareTo() methods.
Now, if you want to sort the elements on the basis of only one attribute the use compareTo() method of comparable interface.
And if you want to sort the elements on the basis of more than one elements then use cmopare() method of comparator interface.

Related

Java Arrays and Inheritance

I always thought that any array type is like a different class but it seems like any reference type arrays are also considered an object of Object[] and their superclasses' array form. (Is this exactly right?)
Consider the following array
Integer[] numbers = { 20, 15, 10, 5 };
When I pass this array to Arrays.sort which expects an Object[] value, it works fine. But an Object doesn't have any method to compare, how does it know which compare method to use?
Integer implements Comparable<Integer> which defines a natural ordering on Integers. Calling sort without a Comparator relies on the elements of the array to implement Comparable, and uses the compareTo method of that interface.
Arrays.sort is used for primitive types and the Object as well.
As per the array elements type those are being sorted by using sort1 but these sort1 methods are private.
If you are tying to sort int array. So you will use method sort(int[] a). It will call the private method sort1:
private static void sort1(int x[], int off, int len) {...}
And this method description is Sorts the specified sub-array of integers into ascending order.
If you are going to sort Object it will call mergeSort method.
But When you look at Integer class file, it implements Comparable<Integer> (Remember although it's subclass of Object):
public final class Integer extends Number implements Comparable<Integer>
So here you don't want to use the Arrays.sort method. By using the compareTo(Integer anotherInteger) method the array can be sorted.

Sort ArrayList using Comparable

I'm working on a project where I need to be able to sort an ArrayList of Car objects by price. In my Car class, I have
public class Car implements Comparable
and in the body of the code is the compareTo method:
public int compareTo(Object o)
{
Car rhs = (Car)o;
if (price > rhs.price)
return 1;
else if (price < rhs.price)
return -1;
else
return 0;
}
I just don't understand how to implement this method to sort by price- what does carList need to be compared to? I know this isn't correct but so far this is the sorting method.
public void sortByPrice()
{
Collections.sort(carList.compareTo(o));
}
Two problems: one syntatical and one conceptual.
The first issue is that while your compareTo is technically correct, you want to type-bind it to Car instead of Object.
public class Car implements Comparable<Car>
Inside of your compareTo method you'd then substitute Object for Car. You would also want to check for null.
The second is that sortByPrice sounds specific, but since compareTo is comparing based on price, that's somewhat okay.
All you'd need to do is call Collections.sort on the actual collection:
Collections.sort(carList);
Normally, one sorts a collection using
Collections.sort(collection)
while collection has to implement Comparable and sort uses the compareTo method to sort collection.
Your Car class must implement Comparable<Car>. Then your compareTo method will have signature:
public int compareTo(Car other) {}
As per the documentation, this method should:
Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
Then given a List<Car>, say list, you can call Collections.sort(list).
You're almost done! Only call to Collections.sort(carList); and that will by itself, use the overridden compareTo.
Actually, when you're not implementing compareTo, you'll have the very basic implementation, and calling Collections.sort(..) will use the basic implementation, which is comparing pointers in that case.

why does TreeSet remove duplicates when they are unequal?

Friends, I am having a problem in getting entire data using TreeSet. I have sorted the TreeSet on some same values.
here is my code:
MyCars class:
class MyCars implements Comparable<MyCars>{
private String number;
private int yearModel;
private double horsePower;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public int getYearModel() {
return yearModel;
}
public void setYearModel(int yearModel) {
this.yearModel = yearModel;
}
public double getHorsePower() {
return horsePower;
}
public void setHorsePower(double horsePower) {
this.horsePower = horsePower;
}
#Override
public int compareTo(MyCars c) {
return Double.compare(this.horsePower,c.getHorsePower());
}
}
SortTest class:
public class SortTest {
void GoForSort(){
Set dataStructure=new TreeSet();
MyCars c1=new MyCars();
c1.setNumber("SRT-Viper123");
c1.setYearModel(2013);
c1.setHorsePower(450.00);
MyCars c2=new MyCars();
c2.setNumber("Chevrolet-Corvette901");
c2.setYearModel(2012);
c2.setHorsePower(450.00);
MyCars c3=new MyCars();
c3.setNumber("Ford-Mustang678");
c3.setYearModel(2014);
c3.setHorsePower(455.00);
dataStructure.add(c1);
dataStructure.add(c2);
dataStructure.add(c3);
Iterator<MyCars> it=dataStructure.iterator();
while(it.hasNext()){
MyCars c=it.next();
System.out.println(c.getNumber()+"\t"+c.getHorsePower()+"\t"+c.getYearModel());
}
}
public static void main(String[] args) {
SortTest st=new SortTest();
st.GoForSort();
}
}
As you can see I have sorted the TreeSet on the basis of horsePower. And I have given SAME value for horse-power to two objects.
Here is the output I get:
SRT-Viper123 450.0 2013
Ford-Mustang678 455.0 2014
But I also want Chevrolet-Corvette901 to come in this set of output. Why I am not getting it.
Is there any way to include that also? Because I found there was NO Problem when I change my collection to ArrayList. Does TreeSet sorts only unique elements?
Is there any trick to get & print all objects during Iteration regardless of their uniqueness in TreeSet...
TreeSet is a child of Set and sets do not store duplicate values. Here is the first line from the definition of set in java docs.
A collection that contains no duplicate elements.
Edit:
As pointed out by #AlexEfimov in the comment below, TreeSet uses the compareTo method to determine the ordering and equality of elements, and so as others have pointed out, the compareTo implementation of MyCars would make the two elements with the same horse power equal, and hence only one of them would be stored in the TreeSet.
Normally with a Set, the uniqueness of the contained objects is determined by their equals() method. In your example, you would implement Car.equals() such that two Cars would be equal if they had the same number, modelYear and horsePower. Then you could add your Corvette into the set and it wouldn't conflict with another model that has the same horsepower.
TreeSet is different: it determines that two objects are identical, not when equals() returns true, but when the compareTo() returns 0. This means you can easily find yourself with two objects that the TreeSet treats as identical, even though they aren't.
Indeed the doc for TreeSet states:
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.
In other words, to not break the Set contract, TreeSet depends on YOU only ever supplying a Comparator that's consistent with the equals() implementation of the objects you put in the set.
Since TreeSet allows you to specify an arbitrary Comparator, we might as well be more succinct and say that TreeSet breaks the Set contract.
You have two options:
Make your compareTo also compare the number and yearModel fields.
Store a collection (array or List) at each node - usually called a MultiSet.
So long as your compareTo reports that two items are equal, only one of them will appear in the set.
Set doesn't store duplicated elements.
If you want to store both of your cars you should change equals and compareTo methods to compare also number. Then both entries will be different.
Remember that equals method should be consistent with compareTo, so I strongly recommend you to override equals method as well.
Sets only store unique elements.
From Wikipedia on a Set
In mathematics, a set is a collection of distinct objects, considered as an object in its own right. For example, the numbers 2, 4, and 6 are distinct objects when considered separately, but when they are considered collectively they form a single set of size three, written {2,4,6}. Sets are one of the most fundamental concepts in mathematics.
A Set has distinct/unique elements, i.e. no duplicates.

Not sure how to sort an ArrayList based on parts of Objects in that ArrayList (Java)

I have a Sorts class that sorts (based on insertion sort, which was the assignment's direction) any ArrayList of any type passed through it, and uses insertion sort to sort the items in the list lexicographically:
public class Sorts
{
public static void sort(ArrayList objects)
{
for (int i=1; i<objects.size(); i++)
{
Comparable key = (Comparable)objects.get(i);
int position = i;
while (position>0 && (((Comparable)objects.get(position)).compareTo(objects.get(position-1)) < 0))
{
objects.set(position, objects.get(position-1));
position--;
}
objects.set(position, key);
}
}
}
In one of my other files, I use a method (that is called in main later) that sorts objects of type Owner, and we have to sort them by last name (if they are the same, then first name):
Directions: "Sort the list of owners by last name from A to Z. If more than one owner have the same last name, compare their first names. This method calls the sort method defined in the Sorts class."
What I thought first was to get the last name of each owner in a for loop, add it to a temporary ArrayList of type string, call Sorts.sort(), and then re-add it back into the ArrayList ownerList:
public void sortOwners() {
ArrayList<String> temp = new ArrayList<String>();
for (int i=0; i<ownerList.size(); i++)
temp.add(((Owner)ownerList.get(i)).getLastName());
Sorts.sort(temp);
for (int i=0; i<temp.size(); i++)
ownerList.get(i).setLastName(temp.get(i));
}
I guess this was the wrong way to approach it, as it is not sorting when I compile.
What I now think I should do is create two ArrayLists (one is firstName, one is LastName) and say that, in a for loop, that if (lastName is the same) then compare firstName, but I'm not sure if I would need two ArrayLists for that, as it seems needlessly complicated.
So what do you think?
Edit: I am adding a version of compareTo(Object other):
public int compareTo(Object other)
{
int result = 0;
if (lastName.compareTo(((Owner)other).getLastName()) < 0)
result = -1;
else if (lastName.compareTo(((Owner)other).getLastName()) > 0)
result = 1;
else if (lastName.equals(((Owner)other).getLastName()))
{
if (firstName.compareTo(((Owner)other).getFirstName()) < 0)
result = -1;
else if (firstName.compareTo(((Owner)other).getFirstName()) > 0)
result = 1;
else if (firstName.equals(((Owner)other).getFirstName()))
result = 0;
}
return result;
}
I think the object should implement a compareTo method that follows the normal Comparable contract--search for sorting on multiple fields. You are correct that having two lists is unnecessary.
If you have control over the Owner code to begin with, then change the code so that it implements Comparable. Its compareTo() method performs the lastName / firstName test described in the assignment. Your sortOwners() method will pass a List<Owner> directly to Sorts.sort().
If you don't have control over Owner, then create a subclass of Owner that implements Comparable. Call it OwnerSortable or the like. It accepts a regular Owner object in its constructor and simply delegates all methods other than compareTo() to the wrapped object. Its compareTo() will function as above. Your sortOwners() method will create a new List<OwnerSortable> out of the Owner list. It can then pass this on to Sorts.sort().
Since you have an ArrayList of objects, ordinarily we would use the Collections.sort() method to accomplish this task. Note the method signature:
public static <T extends Comparable<? super T>> void sort(List<T> list)
What's important here is that all the objects being sorted must implement the Comparable interface, which allows objects to be compared to another in numerical fashion. To clarify, a Comparable object has a method called compareTo with the following signature:
int compareTo(T o)
Now we're getting to the good part. When an object is Comparable, it can be compared numerically to another object. Let's look at a sample call.
String a = "bananas";
String b = "zebras";
System.out.println(a.compareTo(b));
The result will be -24. Semantically, since zebras is farther in the back of the dictionary compared to bananas, we say that bananas is comparatively less than zebras (not as far in the dictionary).
So the solution should be clear now. Use compareTo to compare your objects in such a way that they are sorted alphabetically. Since I've shown you how to compare strings, you should hopefully have a general idea of what needs to be written.
Once you have numerical comparisons, you would use the Collections class to sort your list. But since you have your own sorting ability, not having access to it is no great loss. You can still compare numerically, which was the goal all along! So this should make the necessary steps clearer, now that I have laid them out.
Since this is homework, here's some hints:
Assuming that the aim is to implement a sort algorithm yourself, you will find that it is much easier (and more performant) to extract the list elements into an array, sort the array and then rebuild the list (or create a new one).
If that's not the aim, then look at the Collections class.
Implement a custom Comparator, or change the object class to implement Comparable.

How do I fix a Java Priority-Queue to correctly sort by a specific property?

I have a Java PriorityQueue for sorting objects from a specific class I made called Node. I want it to sort the Nodes by their getData() method. I tried the following code (using a comparator), but it did not work. When I called the priority queue's "poll" method, it did not return the lowest results first, but in a seemingly random order. How do I fix it? Thanks!
PriorityQueue<Node> pq = new PriorityQueue<Node>(hm.size(),
new Comparator<Node>( ) {
// override the compare method
public int compare(Node i, Node j) {
if (i.getData()<j.getData()){
return i.getData(); //It should sort by the Node's getData method.
}
return j.getData();
A comparator needs to return -1 (a negative number), 0 or +1 (a positive number) depending on whether the first operand is less-than, equal-to or greater-than the second operand. You are returning the data itself which won't do what you want.
Rewrite the compare method:
public int compare(Node i, Node j) {
return i.getData() - j.getData()
}
This will follow requirements of compare method to return value less, equal or more than zero depending on comparison result.

Categories