I have an unsorted linked list. To sort it, I thought I'd put the values into a TreeSet with a comparator supplied, then return those values as a new linked list. Yet, it fails.
Comparator:
public class SortSpeciesByCommonName implements Comparator<Species> {
/**
* a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
*/
#Override
public int compare(Species arg0, Species arg1) {
return arg0.getName().compareTo(arg1.getName()); //arg.getName() is String
}
}
Sorting function:
public static LinkedList<Species> sortedAnimals(LinkedList<Species> animals) {
TreeSet<Species> sortedBreeds = new TreeSet<Species>(new SortSpeciesByCommonName());
sortedBreeds.addAll(animals);
return new LinkedList<Species>(sortedBreeds);
}
When testing the values, everything appears to still be in insertion order.
Why don't you use Collections.sort(List,Comparator):
LinkedList<Species> sorted = new LinkedList<Species>(arg);
Collections.sort(sorted, new Comparator<Species>() {
#Override
public int compare(Species s1, Species s2) {
return s1.getName().compareTo(s2.getName());
}
});
We cannot really debug your program and why the list isn't sorted. Can you provide a test case? What's the signature of Species.getName()? Is it a String?
This doesn't answer your question directly, but you may find it easier to just use Collections.sort, passing in your list and comparator. Saves using a TreeSet.
Related
I'm a C# developer trying to work on Java. I'm stuck in creating a dynamic comparator. below is the code
public class SortImpl implements Sort {
public SortImpl() {
}
public ArrayList<Comparable> sort(ArrayList<Comparable> var1) {
Comparator var2 = new Comparator() {
};
var1.sort(var2);
return var1;
}
}
But Comparator needs a type while creating a Comparator object. My ArrayList can be of any type like int, double, float. Please let me know what I am doing wrong.
As I can understand from your code snippet you trying to create sort implementation, not comparator itself.
A Comparator<T> is an object that compare two objects.
From JavaDoc:
int compare(T o1, T o2)
Compares its two arguments for order.
Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
Because list elements already Comparable they can be directly compared as o1.compareTo(o2).
Also sort should be defined as public <T extends Comparable> List<T> sort(List<T> var1).
You don't need to implement a Comparator at all if you use java.util.Collections for sorting the list: it will then be sorted according to the natural ordering of its elements:
public ArrayList<Comparable> sort(ArrayList<Comparable> var1) {
Collections.sort(var1);
return var1;
}
In Java you dont have to implement Comparators for those types (Integer, Float, Char, String, etc...) When you define a List, you will say what type it is:
List<Person> list = new ArrayList<Person>();
When you sort the list, you may use the Collections.sort(List list, Comparator comparator) method. You may invoke it like:
Collections.sort(list, new Comparator<Person>() {
public int compare(Personobject1, Personobject2) {
return 0;//Put your code here
}
});
Parameters:
o1 - the first object to be compared.
o2 - the second object to be compared.
Returns:
a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
See https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html for more information
This question already has answers here:
Sorting an ArrayList of objects using a custom sorting order
(12 answers)
Closed 8 years ago.
I want to sort this list of Emp objects in ascending order based on the marks field.
List<Emp> emp= new ArrayList<Emp>();
public class Emp implements Serializable {
private String empname;
private String section;
private int empId;
private int marks;
...
You need to write a comparator, otherwise the Sort method assumes which fields you want use when sorting.
Collections.sort(emp, new Comparator<Emp>() { public int compare(Emp one, Emp two) {
return one.marks.compareTo(two.marks);
});
In my example i treated the field marks as public, replace one.marks with a getter if you so choose.
Also since you're using ints which do not have a compareTo, do like so:
Collections.sort(list, new Comparator<Emp>() {
public int compare(Emp one, Emp two) {
int cmp = one.getMarks() > two.getMarks() ? +1 : one.getMarks() < two.getMarks() ? -1 : 0;
return cmp;
}
});
You can use a comparator object to sort.
Collections.sort();
does the sorting.
This will work with your List. The method to be used is compareTo.
if (list.size() > 0) {
Collections.sort(list, new Comparator<Emp>() {
#Override
public int compare(final Emp object1, final Emp object2) {
return object1.getMarks().compareTo(object2.getMarks());
}
} );
}
There are two main ways of supporting object comparisons in Java.
You can have your class implement the Comparable interface, which is acceptable when your objects have a natural ordering that you're relying on (for example, alphabetical ordering for strings). This requires classes to implement a compareTo method which defines the comparison rule between instances.
The standard alternative is to instantiate a Comparator for your class, and specify the comparison rule in a compare method.
In your case, the latter option seems more appropriate. The mechanics of the compare method are fairly simple: it takes two instances of your class, returns a negative value if the first is "less than" the second, a positive number if it is "greater", and 0 if they are "equal". For integer-based comparisons, like comparing by marks, the quick trick is to return the difference of the numbers.
Once you have your Comparator defined, sorting is as simple as invoking the Collections.sort method, opting for the method signature which takes a List and a specified Comparator.
List<Emp> emps = new ArrayList<Emp>();
// populate list...
Comparator<Emp> empComparator = new Comparator<Emp>() {
public int compare(Emp e1, Emp e2) {
return e2.getMarks() - e2.getMarks();
}
};
Collections.sort(emps, empComparator);
I have an array myArray[] of objects MyThing which contains X elements. I need to remove elements belonging to the same group, but leaving one representative of each group.
MyThing class has a field groupId
public class MyThing {
private int groupId;
//...other fields
public int getGroupId(){return groupId;}
//getter and setter
}
So I have to compare groupId integer value of array elements (myArray[x].getGroupId()) and remove all element belonging the same group except the first such element in the array.
This way I will get an array of unique elements with only 1 from the same group. For example, if I have an array with a.getGroupId()=1, b.getGroupId()=2, c.getGroupId()=1 after purification, the array will contain only {a,b}, and c will be removed since it's of the same group as a.
Because this is the custom object, I cannot use Set<T>.
Any ideas?
PS. please let me know if I explained this clearly since it's kind of confusing.
A set by definition doesn't contain any duplicates. A set determines if two items are alike, by using either the objects equals()/compareTo(..) method or by using a Comparator. If you only want unique items in your set, implementing the Comparable interface and overriding equals() is what you want to do. BUT in your case, you're only interested in objects in unique groups, so it's then better to create a custom Comparator for the occasion, which you then supply to the Set, telling it to use it, instead of "natural ordering".
Set<MyThing> myThings = new TreeSet<>(new Comparator<MyThing>() {
#Override
public int compare(MyThing o1, MyThing o2)
{
return o1.getGroupId() - o2.getGroupId();
}
});
myThings.addAll(Arrays.asList(myArray));
After creating the set, you add your entire array into it, using the convinience method addAll(..).
(How the comparator sorts your objects is completely up to you to decide.)
You could loop through your array and use a map to keep track of which IDs have already occurred. Then if one was already added to the set, remove it from the array:
Set<Integer> uniqueIDs = new HashSet<Integer>();
for(MyThing thing : MyThings){
int groupID = thing.getGroupId();
if(!uniqueIDs.add(groupID)){
// DUPLICATE, REMOVE IT
}
}
Use a TreeSet and a custom Comparator class that inspects your objects and treats two with the same group as equal.
http://docs.oracle.com/javase/6/docs/api/java/util/TreeSet.html
Algorithm psuedocode:
Create TreeSet
Add all array elements to TreeSet
Convert TreeSet back to array
For a sample implementation: see Martin's answer
Just rewrote the Martin's solution because the comparator is broken, it might overflow
Set<MyThing> myThings = new TreeSet<>(new Comparator<MyThing>() {
#Override
public int compare(MyThing o1, MyThing o2) {
return Integer.compare(o1.getGroupId(), o2.getGroupId());
}
});
myThings.addAll(Arrays.asList(myArray));
Why don't you try something like (semi-pseudo-code here):
List<Integer> uniqGroups = new ArrayList<Integer>();
for (int i = 0; i < myArray.length; i++) {
int groupId = myArray[i].getGroupId();
if (!uniqGroups.contains(groupId)) {
// Hasn't been seen before, keep around
uniqGroups.add(groupId);
}
else {
// Already seen, remove or otherwise clean up the array
myArray[i] = null;
}
}
As you just need to distinguish your objects by groupId, you might override the hashCode() and equals() methods in your class:
class MyThing {
private int groupId;
public int getGroupId(){return groupId;}
// new code to add...
#Override
public int hashCode() {
return groupId;
}
#Override
public boolean equals(Object o) {
return (o instanceof MyThing
&& (groupId == ((MyThing)o).groupId));
}
}
and then, use a HashSet<MyThing> class to remove the MyThing objects in myArray with duplicated groupId:
myArray = new HashSet<MyThing>(Arrays.asList(myArray)).toArray(new MyThing[0]);
How can I sort an array in Java/Android alphabetically?
After that I want to provide the ordered array to a ListView.
Arrays.sort() should do the trick
http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html
it can be done just using
Arrays.sort(myarray);
For more complex sorting see Comparator
Example:
Arrays.sort(some_array, new Comparator<SomeObject>() {
#Override
public int compare(SomeObject entry1, SomeObject entry2) {
return entry1.getSomeData().compareTo(entry2.getSomeData());
}
});
Objects that implement the Comparable interface (like Strings) have a natural ordering (as defined by its compareTo method) so you can just use Arrays.sort():
Arrays.sort(yourArrayOfComparables);
It will directly sort the array and will not make a copy.
If you want a more specific sort that isn't considered "natural" you can create a Comparator for that object:
Comparator<MyObject> comp = new Comparator<MyObject>() {
public int compare(MyObject obj1, MyObject obj2) {
//Code here
}
}
Arrays.sort(yourArrayOfObjects, comp);
The rules for Comparators and Comparables (where the first object is the object itself) is: return a negative if the first object is less than the second, positive for the other way round and 0 if they're equal.
Here is the piece of code that I have used for Java 5.0
TreeSet<Integer> treeSetObj = new TreeSet<Integer>( Collections.reverseOrder() ) ;
Collections.reverseOrder() is used to obtain a comparator in order to reverse the way the elements are stored and iterated.
Is there a more optimized way of doing it?
Why do you think this approach won't be optimized? The reverse order Comparator is simply going to be flipping the sign of the output from the actual Comparator (or output from compareTo on the Comparable objects being inserted) and I would therefore imagine it is very fast.
An alternative suggestion: Rather than change the order you store the elements in you could iterate over them in descending order using the descendingIterator() method.
TreeSet::descendingSet
In Java 6 and later, there is a method on TreeSet called descendingSet() producing a NavigableSet interface object.
public NavigableSet descendingSet()
The descending set is backed by this
set, so changes to the set are
reflected in the descending set, and
vice-versa. If either set is modified
while an iteration over either set is
in progress (except through the
iterator's own remove operation), the
results of the iteration are
undefined.
The returned set has an ordering equivalent to
Collections.reverseOrder(comparator()).
The expression
s.descendingSet().descendingSet()
returns a view of s essentially
equivalent to s.
Specified by:
descendingSet in interface NavigableSet<E>
Returns:
a reverse order view of this set
Since:
1.6
TreeSet<Integer> treeSetObj = new TreeSet<Integer>(new Comparator<Integer>()
{
public int compare(Integer i1,Integer i2)
{
return i2.compareTo(i1);
}
});
there is need to flip the result. But I guess this is just a micro-optimization... Do you really need this ?
Using descendingSet method you can reverse existing treeSet in the class
import java.util.TreeSet;
public class TreeSetDescending {
public static void main(String[] args)
{
// Declare a treeset
TreeSet<Object> ints = new TreeSet<Object>();
ints.add(2);
ints.add(20);
ints.add(10);
ints.add(5);
ints.add(7);
ints.add(3);
// Initialize treeset with predefined set in reverse order
// using descendingSet()
TreeSet<Object> intsReverse = (TreeSet<Object>)ints.descendingSet();
// Print the set
System.out.println("Without descendingSet(): " + ints);
System.out.println("With descendingSet(): " + intsReverse);
}
}
Reverse compare
You can reverse the order of the two arguments in the compare method of your Comparator.
TreeSet t = new TreeSet(new MyComparator());
{
class MyComparator implements Comparator
{
public int compare(Integer i1,Integer i2)
{
Integer I1=(Integer)i1;
Integer I2=(Integer)i2;
return I2.compareTo(I1); // return -I1compareTo(I2);
}
}
}