Sorting ArrayList<Object> by Comparable Interface - java

Actually I want to sort Array List of objects. I am using Comparable interface for this purpose. It is completely working But the problem is that when I am sorting is is giving these two problems.
All name who have 1st letter capital are coming together on the top and all name who have 1st letter small are coming together on the bottom.
All the sorted Capital letters word are coming together after that all the small letter words are coming at bottom together.
Here is my bean
MyShares.java
public class Myshares implements Comparable<Myshares> {
int id, parent;
String name, path, type, shared_with, shared_or_not, upload_request;
public int getParent() {
return parent;
}
public void setParent(int parent) {
this.parent = parent;
}
public String getUpload_request() {
return upload_request;
}
public void setUpload_request(String upload_request) {
this.upload_request = upload_request;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getShared_with() {
return shared_with;
}
public void setShared_with(String shared_with) {
this.shared_with = shared_with;
}
public String getShared_or_not() {
return shared_or_not;
}
public void setShared_or_not(String shared_or_not) {
this.shared_or_not = shared_or_not;
}
#Override
public int compareTo(Myshares another) {
return this.name.compareTo(another.getName());
}
}
This is the output
I think it is based on ASCII code. I want a complete sorted list. Please take a look.

If you are wishing for a case-insensitive sort, I would recommend changing your compareTo() method to instead use the compareToIgnoreCase() method of String - namely:
public int compareTo(Myshares another) {
return this.name.compareToIgnoreCase(another.getName());
}

Change
#Override
public int compareTo(Myshares another) {
return this.name.compareTo(another.getName());
}
to
#Override
public int compareTo(Myshares another) {
return String.CASE_INSENSITIVE_ORDER.compare(this.name, another.getName());
}
or use the more readable and also very good solution posted by nullPainter.

you should adjust your compareTo() method
return this.name.toLowerCase().compareTo(another.getName().toLowerCase());

Replace the compareTo method with:
public int compareTo(Myshares another) {
return this.name.compareToIgnoreCase(another.getName());
}

I gave you some source to an existing Comparator I wrote which does full Alpha Numeric sorting and will work with numbers in the names like 10, 1, etc
To use it you can do: Collections.sort(myList, comparator);
An alternative would also be in your compare method to lowercase both sides. But anytime you have numbers or symbols it will be thrown off so I would personally use the Comparator.
Checkout the GIST with the source code at: https://gist.github.com/gondor/9328de5fa0cce130bc3b

Related

how to create comparator with generic Treeset?

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);

Generic Return type : How to catch a return type from many possible return types?

Writing the title was a bit tricky for this question :p
This is a basic java query!
I am using google cloud and it has different methods, such as launchInstance, listInstances and terminateInstance and so on.. Here, launchInstance will return a type String as Success or Fail, listInstances will return ArrayList, and so forth.
Now, I want a generic return type, so I made a class which has data entries such as status, reason, and dataRequired which will eventually send the data that is required, i.e String or ArrayList or HashMap.
How can I achieve this functionality.
Here is sample code that I was thinking of doing:
public class ResponseHelper {
private String status;
private String reason;
private String type;
private Object data;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void dataRequired(Object data) {
switch(getType()) {
case "ArrayList": this.data=(ArrayList<String>)data;
}
}
}
If you need a Generic return type of any object in Java, just return Object as the type.(Instead of creating a separate new class for it) Then you can check which object it is and do your stuff. Below is a simple program that you can get an idea out of it
public class GenericReturn {
public static void main(String[] args) {
Object output = returnMeSomething(2);
System.out.println(output.getClass().getSimpleName());
output = returnMeSomething(1);
System.out.println(output.getClass().getSimpleName());
output = returnMeSomething(0);
System.out.println(output.getClass().getSimpleName());
}
/** This can return any Object you want as it has Object as return type*/
public static Object returnMeSomething(int num) {
if (num == 1) {
return "Test";
}
else if (num == 2) {
return new HashMap();
}
return new ArrayList();
}
}
This output as below
HashMap
String
ArrayList

ArrayList - Remove the first added object and no repeats

I'm doing an assignment where I have to add a Present to an ArrayList of presents. There can be a maximum of 10 presents in the ArrayList and the present is defined by its type, cost and name, and if these three fields are the same, then it's the same present and it cannot be added to the ArrayList.
When an eleventh present is added, the first present added to the list has to be removed and this new present take its place.
And I'm really stuck.
This is my code so far:
public class GiftList
{
private ArrayList<Present> presents;
public GiftList() {
presents = new ArrayList<Present>();
}
public void addPresent(Present present) {
if (presents.size() <= 10) {
presents.add(present);
}
else {
//**Remove oldest present in list, then
presents.add(present);
}
//**Another if statement for no duplicated presents
}
public class Present
{
private String name;
private String type;
private double cost;
public Present(String name, String type, double cost) {
this.name = name;
this.type = type;
this.cost = cost;
}
}
Hints:
Look on how to implement equals() and hashCode() for Present.
Check: List.remove(int index) and List.contains(Object).
If you add an equals method to your Present object:
public class Present {
private double cost;
private String name;
private String type;
public Present(String name, String type, double cost) {
this.name = name;
this.type = type;
this.cost = cost;
}
public boolean equals(Object o) {
if (o instanceof Present) {
Present p2 = (Present) o;
return name.equals(p2.name) && type.equals(p2.type) && Double.valueOf(cost).equals(p2.cost);
}
return false;
}
public int hashCode() {
return Objects.hash(name, type, cost);
}
}
Then the following code could be used:
List<Present> myList = new ArrayList<Present>() {
#Override
public boolean add(final Present present) {
if (contains(present)) {
return false;
}
if (size() >= 10) {
remove(0);
}
return super.add(present);
}
};
myList.add(new Present("name", "type", 1.0));
For more info, see Object.equals and List.remove.
However, I believe the best way to do this would be to either use a Set which automatically handles the no repeats-problem or some kind of Queue. If some kind of hash-solution is used (e.g. a HashSet) don't forget to implement the hashCode function (more info on hashCode here).
Edit: added the hashCode-implementation after input from # TJamesBoone.
you can just remove the first element by calling
presents.remove(0);
check this
http://www.tutorialspoint.com/java/util/arraylist_remove.htm
For duplication it would be better if you used a Set
But, if you stick with ArrayList, then implement equals/hashcode as already mentioned and now there are
two options:
Either always call remove (for the new object) before adding it, so it always removes oldest entries
or check existence before adding.
Although 2nd option might be more efficient it depends on how you want to utilize your queue (how FIFO is defined for duplicated objects?). If a new object already exists in the list, do you want to update its index, as it was a new entry? if yes you update its status and it will be deleted at a later time than keeping the older one.
Looking at your description I think this could do your job
int rotatingIndex =- 1 ; //variable maintaining current value of the index.-1 when no elements are present
public void addPresent(Present present) {
rotatingIndex = (rotatingIndex + 1)%10;
presents.add(rotatingIndex,present);
}
I would suggest to override equals for Present, and use linkedlist as queue. like;
public class Present
{
private String name;
private String type;
private Double cost;
public Present(String name, String type, Double cost) {
this.name = name;
this.type = type;
this.cost = cost;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Double getCost() {
return cost;
}
public void setCost(Double cost) {
this.cost = cost;
}
#Override
public boolean equals(Object obj){
if(obj == null || !(obj instanceof Present)){
return false;
}
Present anotherPresent = (Present) obj;
if(this.getName() == anotherPresent.getName()
&& this.getCost() == anotherPresent.getCost()
&& this.getType() == anotherPresent.getType()){
return true;
}
return false;
}
}
Gift class:
public class GiftList
{
private LinkedList<Present> presents = new LinkedList() ;
public void addPresent(Present present) {
if (presents.contains(present)){
// do nothing it already exists!!
return ;
}
if(presents.size() <= 10) {
presents.add(present);
}
else {
presents.pop();
//**Remove oldest present in list, then
presents.add(present);
}
//**Another if statement for no duplicated presents
}
}

sorting collection wrt primitive value

suppose, I have a student class with roll number and name. I want to sort it out wrt roll number. I tried the following .Here is my code:
package CollectionDemo;
import java.util.*;
class student1 implements Comparable<student1>{
int rollNo;
String name;
student1(int rollNo,String name){
this.rollNo=rollNo;
this.name=name;
}
#Override
public boolean equals(Object o){
if((o instanceof student1) && (((student1)o).rollNo == rollNo)){
return true;
}
else
{
return false;
}
}
#Override
public int hashCode(){
return 1;
}
public int compareTo(student1 s) {
return s.rollNo;
}
public String toString(){
return "["+rollNo+","+name+"]";
}
}
public class treeSetDemo {
public static void main(String... a){
Set<student1> set=new TreeSet<student1>();
set.add(new student1(102,"Anu"));
set.add(new student1(101,"Tanu"));
set.add(new student1(103,"Minu"));
System.out.println("elements:"+set);
}
}
o/p: elements:[[102,Anu], [101,Tanu], [103,Minu]]
so, its not sorting:( how to make it correct .
thanks for your help.
================================================
thanks for all your help. The following code runs fine, but now I want to know how it works, if i comment out equals and hashcode method.
package CollectionDemo;
import java.util.*;
class student1 implements Comparable<student1>{
int rollNo;
String name;
student1(int rollNo,String name){
this.rollNo=rollNo;
this.name=name;
}
/* #Override
public boolean equals(Object o){
if((o instanceof student1) && (((student1)o).rollNo == rollNo)){
return true;
}
else
{
return false;
}
}
#Override
public int hashCode(){
return 1;
}
*/
public int compareTo(student1 s) {
System.out.println("hello:"+(this.rollNo-s.rollNo));
return this.rollNo-s.rollNo;
}
public String toString(){
return "["+rollNo+","+name+"]";
}
}
public class treeSetDemo {
public static void main(String... a){
Set<student1> set=new TreeSet<student1>();
set.add(new student1(102,"Anu"));
set.add(new student1(101,"Tanu"));
set.add(new student1(103,"Minu"));
System.out.println("elements:"+set);
}
}
OP:
run:
hello:-1
hello:1
elements:[[101,Tanu], [102,Anu], [103,Minu]]
BUILD SUCCESSFUL (total time: 0 seconds)
you have to change compareTo method in bellow way
public int compareTo(student1 s) {
if(s.rollNo == this.rollNo){
return 0;
}else if(s.rollNo > this.rollNo){
return -1;
}else{
return 1;
}
}
- If you want to sort on the basis of only one attribute, then go with java.lang.Comparable<T> Intereface, along with Collections.sort(List l).
- But if you aim is to sort it on the basis of more then one attribute then go for java.util.Comparator<T> along with Collections.sort(List l, Comparator c).
Eg:
import java.util.Comparator;
public class Fruit implements Comparable<Fruit>{
private String fruitName;
private String fruitDesc;
private int quantity;
public Fruit(String fruitName, String fruitDesc, int quantity) {
super();
this.fruitName = fruitName;
this.fruitDesc = fruitDesc;
this.quantity = quantity;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
public String getFruitDesc() {
return fruitDesc;
}
public void setFruitDesc(String fruitDesc) {
this.fruitDesc = fruitDesc;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int compareTo(Fruit compareFruit) {
int compareQuantity = ((Fruit) compareFruit).getQuantity();
//ascending order
return this.quantity - compareQuantity;
//descending order
//return compareQuantity - this.quantity;
}
public static Comparator<Fruit> FruitNameComparator
= new Comparator<Fruit>() {
public int compare(Fruit fruit1, Fruit fruit2) {
String fruitName1 = fruit1.getFruitName().toUpperCase();
String fruitName2 = fruit2.getFruitName().toUpperCase();
//ascending order
return fruitName1.compareTo(fruitName2);
//descending order
//return fruitName2.compareTo(fruitName1);
}
};
}
I think this implementation is close to recommended:
#Override
public int compareTo(Object other) {
if(other == null || !(other instanceOf student)){
throw new IllegalArgumentException();
}
student s = (student) other;
if(this.rollNo > s.rollNo){
return 1;
} else if (this.rollNo < s.rollNo){
return -1;
} else {
return 0;
}
}
If you are using Comparable interface then your compareTo() method should return the comparison not equals method , Google comparable example.
Check this link
In your compareTo method, you are just returning the value of the object you are comparing to. You need to return the difference, of the attribute of the invoking instance and passed instance.
So, change your compareTo method to the below one: -
#Override
public int compareTo(student1 s) {
return this.rollNo - s.rollNo;
}
NOTE: - Only sign is important for Collections.sort, so you don't really need an if-else block to return -1, 0, or 1. Just return the difference. That's all.
P.S : -
Your hashcode implementation is a very poor one. It will put every instances in the same bucket.
#Override
public int hashCode(){
return 1; // All the instances will have the same hashcode.
}
Ideally, you should use only those attributes to calculate the hashCode which you have used to compare your two instances, here its rollNo.
So, rather than returning simply a value 1, you can have some equations, that calculates your hashcode, taking into to consideration your rollNo and a large prime number also.
You can go through Effective Java - Item#9 for more explanation of this topic.
Now, that your code is working fine, lets move to your 2nd doubt.
equals and hashCode methods are not used when you want to compare two objects that will be used while sorting. We override equals and hashCode methods in order to check whether an instance is equal to another instance later on.
So, compareTo method is not concerned with whether you have ocerrided equals ad hashCode method or not. And you can also infer from name as to what the two methods does, and can they be related or not.
Moreover, equals method is defined in Object class, whereas compareTo method is declared in Comparable interface. So, they are not interrelated.
Check the documentation of these methods: - Object#equals, Object#hashCode, and Comparable#compareTo

Sorting a list of objects based on different data members in java

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 ){
........
}
.......

Categories

Resources