in need help with generics ,i have this class:
public class Course<T> {
private T idOrName;
private float avg;
public Course(T idOrName,float avg){
this.idOrName=idOrName;
this.avg=avg;
}
}
....and i need to make the user choose between String or Integer and then create a Treeset and sort it by this generics type.how can i do that if i dont know if its a number or String?? i have a problem with making the comparator :
Set<Course<?>> list=new TreeSet<>(new Comparator<Course<?>(){
#Override
public int compare(Course<?> o1, Course<?> o2) {
// TODO Auto-generated method stub
return 0;
}
});
First you need to indicate that the expected class must be Comparable by proceeding as next
public class Course<T extends Comparable<T>> {
...
}
Then your generic comparator could be something like this:
Set<Course<?>> list = new TreeSet<>(new Comparator<Course<?>>(){
#Override
public int compare(Course<?> o1, Course<?> o2) {
// If idOrName are both of the same class then we use the
// comparator of this class as we know that they are Comparable
if (o1.idOrName.getClass() == o2.idOrName.getClass()) {
return ((Comparable)o1.idOrName).compareTo((Comparable)o2.idOrName);
}
// If they are not of the same class we compare the name of the class
return o1.idOrName.getClass().getName().compareTo(
o2.idOrName.getClass().getName()
);
}
});
Go for duplication of the fields. Any other solution would be more circumstantial. Here I added a toString that unifies both cases.
public class Course {
private int id;
private String name;
private float avg;
public Course(int id, float avg){
this(id, "", avg);
}
public Course(String name, float avg){
this(0, name, avg);
}
private Course(int id, String name, float avg){
this.id = id;
this.name = name;
this.avg = avg;
}
#Override
public String toString() {
return id != 0 ? String.value(id) : name;
}
}
And a comparator (since java 8):
Comparator.comparingInt(course -> course.id)
.thenComparing(course -> course.name);
Comparator.comparingInt(Course::getId)
.thenComparing(Course::getName);
Related
I have a class called x which is a array list and needs to be sorted in Decreasing order by Value.
My Class-
public static class x
{
public int id;
public double value;
public x(int _id, double _value)
{
id = _id;
value = _value;
//System.out.println(Integer.toString(id));
}
public Integer getID(){
return id;
}
public double getValue(){
return value;
}
//Sorting
public static Comparator<x> getComparator(SortParameter... sortParameters) {
return new xComparator(sortParameters);
}
public enum SortParameter {
VAL_DESCENDING
}
private static class xComparator implements Comparator<x> {
private SortParameter[] parameters;
private xComparator(SortParameter[] parameters) {
this.parameters = parameters;
}
public int compare(x o1, x o2) {
int comparison;
for (SortParameter parameter : parameters) {
switch (parameter) {
case VAL_DESCENDING:
comparison = o2.id - o1.id;
if (comparison != 0) return comparison;
break;
}
}
return 0;
}
}
}
I Call it like:
cp = x.getComparator(x.SortParameter.VAL_DESCENDING);
Collections.sort(attr1, cp);
attr1 is my array list
Just for Reference I am following this
I am getting error:
cannot find symbol : variable cp
I am a newbie to java :(
try using Comparator<x> cp = x.getComparator(x.SortParameter.VAL_DESCENDING); to declare it. you can not use a variable until it is declared
I have class ABC
class ABC{
private List<XYZ> xyzList -- Though its list it contains single object;
private String txt;
}
class XYZ{
private long price;
}
I want to sort List abcList based on class XYZ price variable.
Please provide best possible approach for sorting in ascending order.
Have you tried one of these methods:
java.util.Collections.sort(List<T>)
Or
java.util.Collections.sort(List<T>, Comparator<? super T>)
One way is implement Comparable interface in XYZ and override compareTo and then Collections.sort(yourListOfXYZ) will sort the list.
Other way is using Comparator.
Collections.sort(xyzList, new Comparator<XYZ>() {
#Override
public int compare( XYZ e1,XYZ e2) {
return Long.valueOf(e1.getPrice()).compareTo(Long.valueOf(e2.getPrice()));
}
});
Try this
Collections.sort(xyzList);
I would suggest you look into the documentation for the Comparable interface. Possible even with the use of an PriorityQueue.
In you case you either need to make XYZ implement Comparable, provide a Comparator<XYZ> or a simpler option is to unwrap it and just use a List<Double> or a SortedSet<Double> to hold you prices.
Sample code from http://java2novice.com/java-collections-and-util/arraylist/sort-comparator/
public class MyArrayListSort {
public static void main(String a[]){
List<Empl> list = new ArrayList<Empl>();
list.add(new Empl("Ram",3000));
list.add(new Empl("John",6000));
list.add(new Empl("Crish",2000));
list.add(new Empl("Tom",2400));
Collections.sort(list,new MySalaryComp());
System.out.println("Sorted list entries: ");
for(Empl e:list){
System.out.println(e);
}
}
}
class MySalaryComp implements Comparator<Empl>{
#Override
public int compare(Empl e1, Empl e2) {
if(e1.getSalary() < e2.getSalary()){
return 1;
} else {
return -1;
}
}
}
class Empl{
private String name;
private int salary;
public Empl(String n, int s){
this.name = n;
this.salary = s;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String toString(){
return "Name: "+this.name+"-- Salary: "+this.salary;
}
}
I've got a public List<FriendProfile> friends = new ArrayList<FriendProfile>();. I initialize the friends list by reading the information from the server. The FriendProfile object contains a int called private int userPosition;
Once the friends list has been initialized, I would like to sort the friends list by having the FriendProfile object with the highest userPosition at index 0 of the list and then sort by accordingly, index 1 with the second highest userPosition ...
I guess I could write an sorting algorithm, yet I'm looking for prewritten code (maybe the JDK has some methods to offer?)
Help is appreciated!
Use Collections.sort() and specify a Comparator:
Collections.sort(friends,
new Comparator<FriendProfile>()
{
public int compare(FriendProfile o1,
FriendProfile o2)
{
if (o1.getUserPosition() ==
o2.getUserPosition())
{
return 0;
}
else if (o1.getUserPosition() <
o2.getUserPosition())
{
return -1;
}
return 1;
}
});
or have FriendProfile implement Comparable<FriendProfile>.
Implement Comparable Interface.
class FriendProfile implements Comparable<FriendProfile> {
private int userPosition;
#Override
public int compareTo(FriendProfile o) {
if(this.userPosition > o.userPosition){
return 1;
}
return 0;
}
}
Just Call the Collection.sort(List) method.
FriendProfile f1=new FriendProfile();
f1.userPosition=1;
FriendProfile f2=new FriendProfile();
f2.userPosition=2;
List<FriendProfile> list=new ArrayList<FriendProfile>();
list.add(f2);
list.add(f1);
Collections.sort(list);
The List will be sorted.
Now no need to Boxing (i.e no need to Creating OBJECT using new Operator use valueOf insted with compareTo of Collections.Sort..)
1)For Ascending order
Collections.sort(temp, new Comparator<XYZBean>()
{
#Override
public int compare(XYZBean lhs, XYZBean rhs) {
return Integer.valueOf(lhs.getDistance()).compareTo(rhs.getDistance());
}
});
1)For Deascending order
Collections.sort(temp, new Comparator<XYZBean>()
{
#Override
public int compare(XYZBean lhs, XYZBean rhs) {
return Integer.valueOf(rhs.getDistance()).compareTo(lhs.getDistance());
}
});
Use Collections.Sort and write a custom Comparator that compares based on userPosition.
use Comparator with Collections.sort method
java.util.Collections.sort(list, new Comparator<FriendProfile >(){
public int compare(FriendProfile a, FriendProfile b){
if(a.getUserPosition() > b.getUserPosition()){
return 1;
}else if(a.getUserPosition() > b.getUserPosition()){
return -1;
}
return 0;
}
});
see this link
There are two ways to do this.
1.
FriendProfile could implement the interface Comparable.
public class FriendProfile implements Comparable<FriendProfile>
{
public int compareTo(FriendProfile that)
{
// Descending order
return that.userPosition - this.userPosition;
}
}
...
Collections.sort(friendProfiles);
2.
You could write a Comparator.
public class FriendProfileComparator implements Comparator<FriendProfile>
{
public int compare(FriendProfile fp1, FriendProfile fp2)
{
// Descending order
return fp2.userPosition - fp1.userPosition;
}
}
...
Collections.sort(friendProfiles, new FriendProfileComparator());
When comparing objects rather than primitives note that you can delegate on to the wrapper objects compareTo. e.g. return fp2.userPosition.compareTo(fp1.userPosition)
The first one is useful if the object has a natural order that you want to implement. Such as Integer implements for numeric order, String implements for alphabetical. The second is useful if you want different orders under different circumstances.
If you write a Comparator then you need to consider where to put it. Since it has no state you could write it as a Singleton, or a static method of FriendProfile.
You can use java.lang.Comparable interface if you want to sort in only One way.
But if you want to sort in more than one way, use java.util.Compartor interface.
eg:
The class whose objects are to be Sorted on its roll_nos
public class Timet {
String name;
int roll_no;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getN() {
return roll_no;
}
public void setN(int n) {
this.roll_no = n;
}
public Timet(String name, int n) {
this.name = name;
this.roll_no = n;
}
public String toString(){
return this.getName();
}
}
The class for sorting:
public class SortClass {
public void go(){
ArrayList<Timet> arr = new ArrayList<Timet>();
arr.add(new Timet("vivek",5));
arr.add(new Timet("alexander",2));
arr.add(new Timet("catherine",15));
System.out.println("Before Sorting :"+arr);
Collections.sort(arr,new SortImp());
System.out.println("After Sorting :"+arr);
}
class SortImp implements Comparator<Timet>{
#Override
public int compare(Timet t1, Timet t2) {
return new Integer(t1.getN()).compareTo (new Integer((t2.getN())));
}
}
public static void main(String[] args){
SortClass s = new SortClass();
s.go();
}
}
I have this class:
public class Friend {
private String name;
private String location;
private String temp;
private String humidity;
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getHumidity() {
return humidity;
}
public void setHumidity(String humidity) {
this.humidity = humidity;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
I want to sort a List based on name, location, temp and humidity based on user input.
EDIT:The user specifies by which data member the sorting has to be done.
What is the easiest way to do this?
Thank you.
Because you want to sort them by four different standards, implementing Comparable does not make sense. In this case, you may find that creating different Comparators for each sort-by parameter. However, you could implement Comparable for the most logical sort-by field, such as name. Otherwise, comparators are the way to go.
public class FriendNameComparator extends Comparator<Friend> {
// assuming both are non-null for code simplicity; you may wish to change that
public int compare(Friend f1, Friend f2) {
return f1.getName().compareTo(f2.getName());
}
}
public class FriendLocationComparator extends Comparator<Friend> {
// assuming both are non-null for code simplicity; you may wish to change that
public int compare(Friend f1, Friend f2) {
return f1.getLocation().compareTo(f2.getLocation());
}
}
// and so forth
Then, you can use the sort function of the Collections utility class to sort by the given comparator.
Collections.sort(friendsList, new FriendNameComparator()); // sorts by name
Collections.sort(friendsList, new FriendLocationComparator()); // sorts by location
// etc
Java has a static function called Collections.sort(List, Comparator) which sorts a (generified) List of objects given a custom Comparator which, given two objects of the same type, determines which one is ordered before the other.
Your task is to write a function which creates a Comparator which orders the objects based on its arguments and the user specified sort order. For example:
public Comparator<Friend> getComparator(final String sortBy) {
if ("name".equals(sortBy)) {
return new Comparator<Friend>() {
#Override int compare(Friend f1, Friend f2)
return f1.getName().compareTo(f2.getName());
}
};
} else if ("location".equals(sortBy)) {
return new Comparator<Friend>() {
#Override int compare(Friend f1, Friend f2)
return f1.getLocation().compareTo(f2.getLocation());
}
};
} else if ("temp".equals(sortBy)) {
// ...
} else {
throw new IllegalArgumentException("invalid sort field '" + sortBy + "'");
}
}
List list=new ArrayList();
Use If else if for each criteria:
if(location ){
Collections.sort(list, new Comparator () {
public int compare(YourObject o1, YourObject o2) {
return o1.getLocation().compareTo(o2.getLocation());
}
});
}
} else if(temp ){
........
}
.......
I have a class named Person with multiple properties, for example:
public class Person {
private int id;
private String name, address;
// Many more properties.
}
A lot of Person-objects are stored in an ArrayList<Person>. I want to sort this list by multiple sort parameters, and different from time to time. For instance I might one time want to sort by name ascending and then address descending, and another time just by id descending.
And I don't want to create my own sort methods (i.e., I want to use Collections.sort(personList, someComparator). What is the most elegant solution that achieves this?
I think your enum approach is basically sound, but the switch statements really need a more object oriented approach. Consider:
enum PersonComparator implements Comparator<Person> {
ID_SORT {
public int compare(Person o1, Person o2) {
return Integer.valueOf(o1.getId()).compareTo(o2.getId());
}},
NAME_SORT {
public int compare(Person o1, Person o2) {
return o1.getFullName().compareTo(o2.getFullName());
}};
public static Comparator<Person> decending(final Comparator<Person> other) {
return new Comparator<Person>() {
public int compare(Person o1, Person o2) {
return -1 * other.compare(o1, o2);
}
};
}
public static Comparator<Person> getComparator(final PersonComparator... multipleOptions) {
return new Comparator<Person>() {
public int compare(Person o1, Person o2) {
for (PersonComparator option : multipleOptions) {
int result = option.compare(o1, o2);
if (result != 0) {
return result;
}
}
return 0;
}
};
}
}
An example of usage (with a static import).
public static void main(String[] args) {
List<Person> list = null;
Collections.sort(list, decending(getComparator(NAME_SORT, ID_SORT)));
}
You can create comparators for each of properties you might want to sort and then try "comparator chaining" :-) like this:
public class ChainedComparator<T> implements Comparator<T> {
private List<Comparator<T>> simpleComparators;
public ChainedComparator(Comparator<T>... simpleComparators) {
this.simpleComparators = Arrays.asList(simpleComparators);
}
public int compare(T o1, T o2) {
for (Comparator<T> comparator : simpleComparators) {
int result = comparator.compare(o1, o2);
if (result != 0) {
return result;
}
}
return 0;
}
}
One way is to create a Comparator that takes as arguments a list of properties to sort by, as this example shows.
public class Person {
private int id;
private String name, address;
public static Comparator<Person> getComparator(SortParameter... sortParameters) {
return new PersonComparator(sortParameters);
}
public enum SortParameter {
ID_ASCENDING, ID_DESCENDING, NAME_ASCENDING,
NAME_DESCENDING, ADDRESS_ASCENDING, ADDRESS_DESCENDING
}
private static class PersonComparator implements Comparator<Person> {
private SortParameter[] parameters;
private PersonComparator(SortParameter[] parameters) {
this.parameters = parameters;
}
public int compare(Person o1, Person o2) {
int comparison;
for (SortParameter parameter : parameters) {
switch (parameter) {
case ID_ASCENDING:
comparison = o1.id - o2.id;
if (comparison != 0) return comparison;
break;
case ID_DESCENDING:
comparison = o2.id - o1.id;
if (comparison != 0) return comparison;
break;
case NAME_ASCENDING:
comparison = o1.name.compareTo(o2.name);
if (comparison != 0) return comparison;
break;
case NAME_DESCENDING:
comparison = o2.name.compareTo(o1.name);
if (comparison != 0) return comparison;
break;
case ADDRESS_ASCENDING:
comparison = o1.address.compareTo(o2.address);
if (comparison != 0) return comparison;
break;
case ADDRESS_DESCENDING:
comparison = o2.address.compareTo(o1.address);
if (comparison != 0) return comparison;
break;
}
}
return 0;
}
}
}
It can then be used in code for instance like this:
cp = Person.getComparator(Person.SortParameter.ADDRESS_ASCENDING,
Person.SortParameter.NAME_DESCENDING);
Collections.sort(personList, cp);
One approach would be to compose Comparators. This could be a library method (I'm sure it exists somewhere out there).
public static <T> Comparator<T> compose(
final Comparator<? super T> primary,
final Comparator<? super T> secondary
) {
return new Comparator<T>() {
public int compare(T a, T b) {
int result = primary.compare(a, b);
return result==0 ? secondary.compare(a, b) : result;
}
[...]
};
}
Use:
Collections.sort(people, compose(nameComparator, addressComparator));
Alternatively, note that Collections.sort is a stable sort. If performance isn't absolutely crucial, you sort be the secondary order before the primary.
Collections.sort(people, addressComparator);
Collections.sort(people, nameComparator);
Comparators lets you do that very easily and naturally. You can create single instances of comparators, either in your Person class itself, or in a Service class associated to your need.
Examples, using anonymous inner classes:
public static final Comparator<Person> NAME_ASC_ADRESS_DESC
= new Comparator<Person>() {
public int compare(Person p1, Person p2) {
int nameOrder = p1.getName().compareTo(p2.getName);
if(nameOrder != 0) {
return nameOrder;
}
return -1 * p1.getAdress().comparedTo(p2.getAdress());
// I use explicit -1 to be clear that the order is reversed
}
};
public static final Comparator<Person> ID_DESC
= new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return -1 * p1.getId().comparedTo(p2.getId());
// I use explicit -1 to be clear that the order is reversed
}
};
// and other comparator instances as needed...
If you have many, you can also structure your comparators code any way you like. For example, you could:
inherit from another comparator,
have a CompositeComparator that agregates some existing comparators
have a NullComparator that handle null cases, then delegates to another comparator
etc...
I think coupling the sorters to the Person class, like in your answer, isn't a good idea, because it couples the comparison (usually business driven) and the model object to close to each other.
Each time you want to change/add something the sorter, you need to touch the person class, which is usually something you do not want to do.
Using a Service or something similar, which provides Comparator instances, like KLE proposed, sounds way more flexible and extensible.
My approach is build on Yishai's. The main gap is that there is no way to sort first ascending for an attribute and after that decending for an other one. This can not be done with enumerations. For that I used classes. Because the SortOrder strongly depends on the type I prefered to implement it as an inner class of person.
The class 'Person' with inner class 'SortOrder':
import java.util.Comparator;
public class Person {
private int id;
private String firstName;
private String secondName;
public Person(int id, String firstName, String secondName) {
this.id = id;
this.firstName = firstName;
this.secondName = secondName;
}
public abstract static class SortOrder implements Comparator<Person> {
public static SortOrder PERSON_ID = new SortOrder() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getId()).compareTo(p2.getId());
}
};
public static SortOrder PERSON_FIRST_NAME = new SortOrder() {
public int compare(Person p1, Person p2) {
return p1.getFirstName().compareTo(p2.getFirstName());
}
};
public static SortOrder PERSON_SECOND_NAME = new SortOrder() {
public int compare(Person p1, Person p2) {
return p1.getSecondName().compareTo(p2.getSecondName());
}
};
public static SortOrder invertOrder(final SortOrder toInvert) {
return new SortOrder() {
public int compare(Person p1, Person p2) {
return -1 * toInvert.compare(p1, p2);
}
};
}
public static Comparator<Person> combineSortOrders(final SortOrder... multipleSortOrders) {
return new Comparator<Person>() {
public int compare(Person p1, Person p2) {
for (SortOrder personComparator: multipleSortOrders) {
int result = personComparator.compare(p1, p2);
if (result != 0) {
return result;
}
}
return 0;
}
};
}
}
public int getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getSecondName() {
return secondName;
}
#Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append("Person with id: ");
result.append(id);
result.append(" and firstName: ");
result.append(firstName);
result.append(" and secondName: ");
result.append(secondName);
result.append(".");
return result.toString();
}
}
An example for using the class Person and its SortOrder:
import static multiplesortorder.Person.SortOrder.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import multiplesortorder.Person;
public class Application {
public static void main(String[] args) {
List<Person> listPersons = new ArrayList<Person>(Arrays.asList(
new Person(0, "...", "..."),
new Person(1, "...", "...")
));
Collections.sort(listPersons, combineSortOrders(PERSON_FIRST_NAME, invertOrder(PERSON_ID)));
for (Person p: listPersons) {
System.out.println(p.toString());
}
}
}
oRUMOo
I recently wrote a Comparator to sort multiple fields within a delimited String record. It allows you to define the delimiter, record structure and sorting rules (some of which are type-specific). You can use this by converting a Person record into a delimited String.
Required information is seeded to the Comparator itself, either programmatically or through an XML file.
XML is validated by a package embedded XSD file. For example, below is a tab delimited record layout with four fields (two of which are sortable):
<?xml version="1.0" encoding="ISO-8859-1"?>
<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<delimiter> </delimiter>
<column xsi:type="Decimal">
<name>Column One</name>
</column>
<column xsi:type="Integer">
<name>Column Two</name>
</column>
<column xsi:type="String">
<name>Column Three</name>
<sortOrder>2</sortOrder>
<trim>true</trim>
<caseSensitive>false</caseSensitive>
<stripAccents>true</stripAccents>
</column>
<column xsi:type="DateTime">
<name>Column Four</name>
<sortOrder>1</sortOrder>
<ascending>true</ascending>
<nullLowSortOrder>true</nullLowSortOrder>
<trim>true</trim>
<pattern>yyyy-MM-dd</pattern>
</column>
</row>
You would then use this in java like so:
Comparator<String> comparator = new RowComparator(
new XMLStructureReader(new File("layout.xml")));
Library can be found here:
http://sourceforge.net/projects/multicolumnrowcomparator/
Suppose a class Coordinate is there and one has to sort it in both ways according to X-coordinate and Y-coordinate. Two differnet comparators is needed for it. Below is the sample
class Coordinate
{
int x,y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
static Comparator<Coordinate> getCoordinateXComparator() {
return new Comparator<Coordinate>() {
#Override
public int compare(Coordinate Coordinate1, Coordinate Coordinate2) {
if(Coordinate1.x < Coordinate2.x)
return 1;
else
return 0;
}
// compare using Coordinate x
};
}
static Comparator<Coordinate> getCoordinateYComparator() {
return new Comparator<Coordinate>() {
#Override
public int compare(Coordinate Coordinate1, Coordinate Coordinate2) {
if(Coordinate1.y < Coordinate2.y)
return 1;
else
return 0;
}
// compare using Coordinate y
};
}
}