Java Comparable issue [duplicate] - java

This question already has answers here:
sort arraylist of complex objects alphabetically
(2 answers)
Closed 9 years ago.
I want to sort objects by a string they have. Just wondering does this make sense?
Before now I have only used Arrays.sort(BlahList); But now I could have many objects and not just an arraylist of strings.
public class Contact implements Comparable
{
private string name;
public compareTo (Contact Contact1)
{
return this.name.compareTo(Contact1.name);
}
}
and in the main method I have:
Collections.sort(ContactList);
I would also like to know if this would work for integers if the name was age?

Firstly, you should type the Comparable interface:
public class Contact implements Comparable<Contact>
Secondly, you should use leading lowercase for your parameters/variables:
public compareTo (Contact contact)
Thirdly, prefer not using this. unless necessary - it's just code clutter:
return name.compareTo(contact.name);
And finally, yes, you can compare age like this:
return age - contact.age; // order youngest to oldest
Or the cleaner way (thanks for pointing this out JB):
return Integer.compareTo(age, contact.age);
This whole class should look like this:
public class Contact implements Comparable<Contact> {
private string name;
public int compareTo(Contact contact) {
return name.compareTo(contact.name);
}
}
Note: You were missing the return type int from the code for your compareTo() method.
To compare age instead, replace the compareTo() method with this:
public int compareTo(Contact contact) {
return Integer.compareTo(age, contact.age);
}

it works for all. if it is int u need to write following code in compareTo method
return this.age-contact1.age// for ascending order
contact1.age-this.age // for descending order

In java 7 you can use Integer.compare(age, contact.age).
Its (almost) same as (x < y) ? -1 : ((x == y) ? 0 : 1); but much more readable (Integer.compare does not say it will return those exact numbers, but Oracle's implementation will, it could return any other positive instead of 1 and negative instead of -1)
btw. DON't use age-contact.age, beacause Integer.MIN_VALUE-Integer.MAX_VALUE = 1
For complex comparators (eg. first by name then by age if name is equal) I suggest use some library like google guava.

If you want multiple comparators then I would suggest you to use Comparator interface:
For Name compare:
public class NameCompare implements Comparator<Contact> {
#Override
public int compare(Contact a, Contact b) {
if (a.getName().compareToIgnoreCase(b.getName())>0)
return 1;
else if (a.getName().compareToIgnoreCase(b.getName())<0)
return -1;
return 0;
}
}
For Age Compare:
public class AgeCompare implements Comparator<Contact> {
#Override
public int compare(Contact a, Contact b) {
if (a.getAge() > b.getAge())
return 1;
else if (a.getAge() < b.getAge())
return -1;
return 0;
}
}
And in the main, you just pass the desired Comparator:
ArrayList al = new ArrayList<Contact>
Collections.sort(al, new NameCompare())
Collections.sort(al, new AgeCompare())

Related

How to implement compareTo for any types of comparable objects

I don’t know how I can compare 2 comparable objects without some other variable which tells me which is larger. The question is: Create a class called Max that provides a single class method called max. max takes two arguments to objects that can be compared—that is, that implement the Java Comparable interface as shown above. It returns a reference to whichever is larger. If the two objects are equal, you should return the first. How Comparable is implemented is up to each class, and your method will be called on multiple different kinds of objects.
It gives the int compareTo (Object other) method in the interface but I’m having trouble finding a solution.
public class Max implements Comparable
{
public int compareTo(Object other)
{
}
public static Comparable max(Comparable first, Comparable second)
{
int fi = first.compareTo(second);
if(fi >0)
return first;
else if (fi<0)
return second;
return first;
}
}
java.lang.AssertionError: Class should not implement Comparable: expected [false] but found [true]
That is one of the errors. But also I need help writing the compareTo method.
I deleted my previous answer because I think, imho, you are over complicating this. Since the two arguments to max have implemented the Comparable<T> interface, all you have to do is call it as:
int ret = first.compareTo(second);
Then return first or second like you are doing based on the value of ret. That way you don't need to know anything about how it was implemented. Perhaps you could get some clarification from either your instructor or someone else who is working on this (I presume it is for an assignment).
It would be worthwhile for you to create some test classes which implement the interface. You can just make up some variable that represents size.
The keyword for your question is generics. You might want to do some research and read something about it. Take a look at the following example. I've implemented the class Max as a static class to keep it simple:
import java.time.LocalDate;
public class MyTestClass{
public static void main(String args[]) {
Integer i = 16;
Integer j = 15;
Integer m = Max.max(i, j);
System.out.println(m);
String k = "aaaa";
String n = "zzzz";
String s = Max.max(k, n);
System.out.println(s);
LocalDate d = LocalDate.now();
LocalDate e = LocalDate.now().plusDays(2);
LocalDate f = Max.max(d , e);
System.out.println(f);
}
static class Max{
public static <T extends Comparable> T max(T first, T second) {
if (first.compareTo(second) >= 0)
return first;
else
return second;
}
}
}
As you can see, there is a class Max with a single method max which accepts two objects, for example two integers, two strings or two date objects.
Since all these classes implement the comparable interface, you can use the max method for all object types. The compiler then decides during the runtime which comapreTo method to call, that is the compareTo of the class Integer, String, LocalDate or whatever.

How to sort an Array list using attributes from different classes [duplicate]

This question already has answers here:
Collections.sort with multiple fields
(15 answers)
Closed 6 years ago.
//For Class A
public class NameCompare implements Comparator<A>
{
public int compare(A a1, A a2){
if(a1.findName()> a2.findName()){
return 1;
}
else if(a1.findName()== a1.findName())
return 0;
else {
return -1;
}
}
}
//For Class B
public class ACompare implements Comparator<B>
{
public int compare(B b1, B b2){
if(b1.getId()> b2.getId()){
return 1;
}
else if((b1.getId()== (b2.getId()())
return 0;
else {
return -1;
}
}
}
//Main Class
ArrayList<A> copy = (ArrayList<A>)B.getA();
Collections.sort(copy, new NameCompare());
Collections.sort(copy, new ACompare());
for (A a : copy) {
System.out.println(a);
}
I am new to Java. As far as I know, the method above may be an incorrect way to sort a list by using the attributes from 2 different classes. Assuming class B holds an array list of class A. How would I sort the list, lets say I would want to display an ascending id, then the name
Your question is not completely clear, but I would suggest that (using your example of name and id) you define a class Person with two fields: name and id. Then you can define a comparator that compares the id first and then the name. In this way, you can sort objects of type Person in the right way.
If you need to have "lists of lists", that should be sorted, then you need to explain your issue more thoroughly.

Java Sorting Objects with Multiple Parameters

I have recently been working to better my understanding of sorting algorithms and their relationship to different types of input. Currently, I'm working on a Student Management program where each student has three parameters: Last Name, GPA, and User ID (String, double, int). They are each stored in a Student class with those three parameters, and there are DOZENS of students (a key feature of the program is to input, remove, and update students).
My question is: using the major sorting algorithms (mergesort, quicksort, etc.), what is the best way to sort my list of students by each parameter? For instance, what is the best way to perform a mergesort to sort the list by GPA? Or to use quicksort to sort the list by last name?
Essentially my question boils down to...I can sort these objects if they didn't have three parameters (writing a mergesort to sort 100 numbers is very easy for me). How do I manage the other two parameters and make sure they're accessible after the sort?
The way this is done in Java is to use different Comparators. Then you say:
Collections.sort(list, new NameComparator());
Or
Collections.sort(list, new GpaComparator());
These comparators use different fields to define the order between two elements.
For example, Name Comparator might be:
class NameComparator implements Comparator< Student> {
#Override public int compare(Student left, Student right) {
return left.getName().compareTo(right.getName());
}
}
And GpaComparator might be
class GpaComparator implements Comparator< Student> {
#Override public int compare(Student left, Student right) {
if (left.getGpa() < right.getGpa()) {
return -1;
} else if (left.getGpa() > right.getGpa()) {
return 1;
} else {
return 0;
}
}
The typical way to do this is to write a generic sorting algorithm on any type that accepts a Comparator, and then to write different Comparators to sort by different fields.
I would recommend implementing the Comparable interface in your Student Class like this
public class Student implements Comparable {
public int compareType; //you can make this an enum if you want
...
public int compareTo(Object o) {
if(compareType == 0)
return gpaCompareTo(o);
else if(compareType == 1)
return nameCompareTo(o);
return idCompateTo(o);
}
public int gpaCompareTo(Object o) {
//implement your gpaCompareTo
}
public int nameCompareTo(Object o) {
//implement your nameCompareTo
}
public int idCompareTo(Object o) {
//implement your idCompareTo
}
}
And then use a built-in sort like
List<Student> list = new ArrayList<Student>();
...
Collections.sort(list);
Or you can not implement Comparable and design your own comparators
public class MyComparator implements Comparator<Student> {
public int compare(Student o1, Student o2) {
//implement the comparator
}
public boolean equals(Object o) {
//implement the equals
}
}
Then you can use the other Collection's sort method
Collections.sort(list, MyComparator);
This is probably off topic, but if you want to try something cool, the JDK 8 Lambda Preview offers a few cool ways to define comparators using Lamda expressions and method references.
Let's say we have a class:
class Jedi {
private final String name;
private final int age;
//...
}
And then a collection of them:
List<Jedi> jediAcademy = asList(new Jedi("Obiwan",80), new Jedi("Anakin", 30));
sort(jediAcademy, (j1, j2) -> j1.getAge() > j2.getAge() ? 1 : j1.getAge() < j2.getAge() ? -1 : 0);
System.out.println(jediAcademy); //Anakin, Obiwan
Or with method references, supposing Jedi has method that behaves as a comparator (same signature)
class Jedi {
public static int compareByAge(Jedi first, Jedi second){
return first.age > second.age ? 1 : first.age < second.age ? -1 : 0;
}
//...
}
Which could be used as follows to generate a comparator by using a method reference:
List<Jedi> jediAcademy = asList(new Jedi("Obiwan",80), new Jedi("Anakin", 30));
sort(jediAcademy, Jedi::compareByAge);
System.out.println(jediAcademy);//Anakin, Obiwan
It's really no different than sorting numbers, except that in this case your "digits" are the three fields of your users, the value of each digit is constrained by the values of each field, and the order of the fields determines the sort ranking.
To be a bit more specific, you have a Tupple with 3 fields: <GPA, Last Name, User ID>, and lets assume that you want to sort by GPA, and then Last Name, and the User ID.
In the same way that 219 is sorted above 139 (ie. the "hundreds" digit has a higher value even though the "tens" digit is lower), a tupple like <3.75, Jones, 5> will be sorted above <3.0, Adams, 2> because the "GPA digit" (which is more significant) has a higher value, even though the "last name digit" is lower (eg. Jones is "lower" than Adams).
Use multiple comparators
class Student
{
String lastName;
dounle GPA;
int userId
static Comparator<Student> getStudentLastNameComparator() {
return new Comparator<Student>() {
#Override
public int compare(Student Student1, Student Student2) {
return Student1.getlastName().compareTo(Student2.getlastName());
}
// compare using Student lastName
};
}
static Comparator<Student> getStudentGPAComparator() {
return new Comparator<Student>() {
#Override
public int compare(Student Student1, Student Student2) {
if(Student1.GPA < Student2.GPA)
return 1;
else
return -1;
}
// compare using Student GPA
};
}
static Comparator<Student> getStudentUserIdComparator() {
return new Comparator<Student>() {
#Override
public int compare(Student Student1, Student Student2) {
if(Student1.userId < Student2.userId)
return 1;
else
return -1;
}
// compare using Student userId
};
}
}

Best way for custom sorting in Java?

I am a C++ programmer and I am using Java at the moment (I do have a considerable amount of java experience).
Basically, I want to recreate the pair<int,int> that I so commonly use in C++ and I want to have it sorted by the second integer value.
I am searching up on the internet and trying different ways of going about this, including using Comparator, Comparable etc.
I am basically creating a test program that looks like this:
import java.math.*;
import java.util.*;
import java.io.*;
import java.text.*;
class PairTest
{
public static void main (String args[]) // entry point from OS
{
new PairTest().run();
}
public void run (){
Pair foo = new Pair(1,2);
System.out.println(foo.first + " "+ foo.second);
ArrayList <Pair> al = new ArrayList<Pair>();
for(int i =10;i>0;i--){
al.add(new Pair(i, i*2));
}
for(int i =0;i<al.size();i++){
System.out.println(al.get(i).first + " " + al.get(i).second);
}
Collections.sort(al);
for(int i =0;i<al.size();i++){
System.out.println(al.get(i).first + " " + al.get(i).second);
}
}
private class Pair implements Comparable{
public int first;
public int second;
public Pair (int a, int b){
this.first = a;
this.second = b;
}
int compareTo (Pair o){
return new Integer(this.second).compareTo(new Integer(o.second));
}
}
}
What would be the best way to go about making a custom sorting function so the ArrayList sorts by the "second" variable. I want a quick and safe way of doing it, and at the moment, the compiler is telling me that "PairTest.Pair does not override abstract method compareTo..."
I really don't know whats going on, any help would be greatly appreciated.
There are two problems with your Pair class: it does not declare a generic parameter and the compareTo method needs to be public. Also, it is more efficient to just return the difference between int values than to construct Integer objects and invoke compareTo. Try this:
private class Pair implements Comparable<Pair> {
public int first;
public int second;
public Pair (int a, int b){
this.first = a;
this.second = b;
}
public int compareTo (Pair o){
return second < o.second ? -1 : (second == o.second ? 0 : 1);
}
}
In your code, you should change:
private class Pair implements Comparable
to
private class Pair implements Comparable<Pair>
And you change this line:
int compareTo (Pair o)
to
public int compareTo (Pair o)
because this function will be use outside of this class :)
That's all you need :)
Override comapreTo method in your Pair class. No need to implement anything.
comapreTo method accepts Object as the argument
public int compareTo(Object another)
{
return new Integer(this.second).compareTo(new Integer(((Pair)another).second));
}

How find if arraylist contains a value which is in class field?

I have class:
static class AnotherClass {
int number;
String isPrime;
public int getNumber() {
return number;
}
public String getPrime() {
return isPrime;
}
public void setNumber(int number) {
this.number = number;
}
public void setPrime(String prime) {
isPrime = prime;
}
}
and in main class i have:
List<AnotherClass> listx = new ArrayList<AnotherClass>();//just a arraylist
for (int z = 0; z < howManyQuestions; z++) {//in loop i add class with fields
AnotherClass classx = new AnotherClass();
int valuex = Integer.parseInt(keyboardkey.readLine());
classx.setNumber(valuex);//save value in this class
String answer = Check(valuex);//i just get here string answer YES NO
classx.setPrime(answer);
listx.add(classx);//and i add this two fields of class to list
System.out.println();
}
INPUT: (i add value and check if it was input before)
3
4
3
OUTPUT
NO
NO
YES
How can i check if, for example value "3" is containing by list?
1 AnotherClass must implement equals() (and implement hashCode() accordingly).
2 Use method contains(Object o) from listx.
private boolean contains(int i)
{
for(int j: listx.getNumber()) { if(i == j) return true; }
return false;
}
A Few notes -
your class doesn't require static. That has a use if you're declaring an inner class.
You have a container class holding a string that's dependant on an int, as well as the int. It'd be more idiomatic to have the check inside your class, e.g.
class AnotherClass {
int number;
public int getNumber() {
return number;
}
public String getPrime() {
return check(number)
}
private boolean check() { ... whatever logic you had .. }
}
If you're looking for "contains" functionality, you'd probably use a HashSet, or a LinkedHashSet( if you want to preserve the ordering ). If you want to do this with your created class you'll need to implement a hashCode() method to tell the hashSet how to know if it has a duplicate value.
Or you can just iterate over your list.
You have to implement equals() for AnotherClass. The default equals() compares identity instead of value equality.
The javadoc for List.contains() says:
Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).

Categories