Using compareTo and Collections.sort - java

I have a franchise class with owner(owner of franchise's name), state(2-character string for the state where the franchise is located), and sales (total sales for the day)
public class Franchise implements Comparable <Franchise> {
final String owner;
final String state;
final double sales;
protected Franchise(String owner, String state, double sales ) {
this.owner = owner;
this.state = state;
this.sales = sales;
}
public String toString() {
String str = state + ", " + sales + ", " + owner;
return str;
}
public String getState() {
return state;
}
public double getSales() {
return sales;
}
public int compareTo(Franchise that) {
double thatSales = that.getSales();
if (this.getState().compareTo(that.getState()) < 0)
return -1;
else if (this.getSales() > thatSales)
return -1;
else if (this.getSales() < thatSales)
return 1;
else
return 0;
}
}
the compareTo is based on state ASCENDING and sales DESCENDING
import java.util.ArrayList;
import java.util.Collections;
public class FranchiseTester {
public static void main(String[] args) {
ArrayList<Franchise> franchises = new ArrayList<Franchise>();
Franchise a = new Franchise("Andrew Luck", "IN", 1270.5);
Franchise b = new Franchise("Ray Rice", "MD", 1210);
Franchise c = new Franchise("Alfred Morris", "WA", 980.5);
Franchise d = new Franchise("Roddy White", "GA", 670);
Franchise e = new Franchise("Greg Olsen", "SC", 740);
Franchise f = new Franchise("T.Y. Hilton", "IN", 950);
Franchise g = new Franchise("Julio Jones", "GA", 560);
franchises.add(a);
franchises.add(b);
franchises.add(c);
franchises.add(d);
franchises.add(e);
franchises.add(f);
franchises.add(g);
Collections.sort(franchises);
for(int i = 0; i < franchises.size(); i++) {
System.out.print(franchises.get(i) + "\n");
}
}
}
when I compare these franchise objects without the Collections.sort they compare correctly, However when I test using the Collections.sort like I have here I get an output like this:
GA, 670.0, Roddy White
GA, 560.0, Julio Jones
IN, 1270.5, Andrew Luck
IN, 950.0, T.Y. Hilton
MD, 1210.0, Ray Rice
SC, 740.0, Greg Olsen
WA, 980.5, Alfred Morris
The state's are still being compared correctly but it's not comparing by sales properly (lower sales for particular stat should come first)
I think that the .sort compares string by default is the reason that states are still correct, my question is how do I implement it to compare based on sales too?

In your problem statement you are saying that "compareTo is based on state ASCENDING and sales DESCENDING". Based on this your results are valid. States are in ascending order and for each state the sale is in descending order. In the very next statement you are saying (lower sales for particular stat should come first). So basically you have two conflicting requirement. Both can not be done simultaneously.
In other words do you want your program to do something else like both should be ascending or both descending or some other order. If yes then you have to modify your compareTo method accordingly.

You have to modify your compareTo method. Cause you are returning after comparing the state. So you have to compare state but sales too.
For example:
public int compareTo(Franchise that) {
int stateComparition = this.getState().compareTo(that.getState());
Double sales = Double.valueOf(this.getSales());
Double thatSales = Double.valueOf(that.getSales());
int salesComparition = sales.compareTo(thatSales);
if(stateComparition == 0){
if(salesComparition > 0)
return -1;
else if(salesComparition < 0)
return 1;
else
return 0;
}
return stateComparition;
}

It is because at first comparision condition you are comparing on the basis of state. If the state of current object is not small, then only comparision based on sales will take place. According to your code, in state you want the state of current object to be less than the comparing state, however in sales comparision you want the sales of current object to be greater than the comparing object. This is why you are getting different results. States are being compared in ascending order and sales in descending order. It is all dependent on what you return from compareTo function.
public int compareTo(Franchise that) {
double thatSales = that.getSales();
if (this.getState().compareTo(that.getState()) < 0)
return -1;
else if (this.getSales() < thatSales)
return -1;
else if (this.getSales() > thatSales)
return 1;
else
return 0;
}
Hope this code will help you. You can find good explanation over here

Comparable will give only one way of comparision. This can be done using Comparator interface too.
Collections.sort(list, new Comparator<Franchise>() {
#Override
public int compare(Franchise obj1, Franchise obj2) {
if(obj1.getState().compareTo(obj2.getState()) == 0)
{
Double a1 =obj1.getSales();
Double a2 = obj2.getSales();
return a2.compareTo(a1);
}
return obj1.getName().compareTo(obj2.getName());
}
}

Related

Ordering the results of an file with ArrayList and compareTo

I have to order an arrayList that contains lines from a file by account ID and then by salary to get this result:
CuentaAhorro : 11111111A (Alicia) Saldo 111,11
CuentaAhorro : 12345678A (Lucas) Saldo 5100,00
CuentaCorriente: 22222222B (Peio) Saldo 222,22
CuentaAhorro : 33333333C (Isabel) Saldo 4433,33
CuentaCorriente: 33333333C (Isabel) Saldo 3333,33
CuentaAhorro : 87654321A (Asier) Saldo 3000,00
My arrayList calls the compareTo method from Bank.java.
public void ordenarCuentas() {
Collections.sort(cuentas);
}
The call is to the method compareTo in an abstract class called Account with the comparable interface:
#Override
public int compareTo(Cuenta unaCuenta) {
Cliente unTitular = unaCuenta.titular;
if(unTitular.toString().equals(unaCuenta.titular.toString()) == true) {
return 0;
// if(saldo < unaCuenta.saldo) {
// return -1;
// } else if (saldo > unaCuenta.saldo) {
// return 1;
// } else {
// return 0;
// }
}
return -1;
}
I need to check if the object 'Cuenta unaCuenta' passed as a parameter has the same account number as another and then sort by the amount of money in the account, however I am not sure how to get the condition right, as you can see, with the commented if I get the salary in the right descending order but not the account IDs.
The object Cuenta unaCuenta contains titular which contains account number and name.
The object Cliente unTitular contains the account number and name.
Could somebody lend me a hand please?
I am not able understand it very clearly because of language barrier
But if you have a arraylist you can call sort method on it an pass a comparator to get the desired sorting , something like below.
It is just to give you an idea
ArrayList<String> list = new ArrayList<>();
list.sort(new Comparator() {
#Override
public int compare(Object o1, Object o2) {
if(o1.account.equals(o2.account)) return 0;
return o1.amount - o2.amount;
}
});
as Lambda
ArrayList<String> list = new ArrayList<>();
list.sort((o1,o2) ->
if(o1.account.equals(o2.account)) return 0;
return o1.amount - o2.amount;
});
Thank you everyone for the comments. Next time i'll translate the Spanish code to English. I'll post my solution incase someone comes across this question.
(in my case I had to use a comparable interface and a compareTo method).
#Override
public int compareTo(Account anAccount) {
String b = this.title.toString();
Client aTitle = anAccount.title;
String c = aTitle.toString();
if(b.compareTo(c) == 0) {
if(balance == anAccount.balance) {
return 0;
} else if (balance < anAccount.balance) {
return 1;
} else {
return -1;
}
}
return b.compareTo(c);
}
As stated, I had to compare both object values first, if they are the same I then check the condition of the balance to change the order.
-1 = object is less than the parameter.
0 = when both objects are the same.
1 = the object is more than the parameter.
And I called the method from the Bank.java class with:
Collections.sort(cuentas);
Where cuentas is the ArrayList.

How to alter a bubble sort from numeric to alphabetical?

I am using an ArrayList with book titles and book ratings. How can I change this code to make the bubble sort for alphabetical instead of numeric?
System.out.println("\r" + "In order by rating");
for (int out = 0; out < bookList.size(); out++) {
for (int in = 0; in < bookList.size() - 1; in++)
if (bookList.get(in).getRating() < bookList.get(in + 1).getRating()) {
Book temp = bookList.get(in);
bookList.set(in, bookList.get(in+1));
bookList.set(in+1, temp);
}
System.out.println(videoList.get(out).getTitle() + " " + videoList.get(out).getRating());
}
}
My other classes are below.
Book
public class Book {
String title;
int rating;
public Book(String pTitle, int pRating) {
title = pTitle;
rating = pRating;
}
public String getTitle() {
return title;
}
public int getRating() {
return rating;
}
public void setTitle(String newTitle) {
title = newTitle;
}
public void setRating(int newRating) {
rating = newRating;
}
}
Library
import java.util.ArrayList;
public class Library {
public static void main (String [] args) {
ArrayList<Book> bookList = new ArrayList<Book>();
Book b1 = new Book ("Huckleberry Finn", 5);
Book b2 = new Book ("The Great Gadsby", 2);
Book b3 = new Book ("Harry Potter", 3);
Book b4 = new Book ("Animal Farm", 4);
Book b5 = new Book ("The Mist", 1);
bookList.add(b1);
bookList.add(b2);
bookList.add(b3);
bookList.add(b4);
bookList.add(b5);
System.out.println("Original sequence");
for (int cnt = 0; cnt < videoList.size(); cnt++) {
System.out.println(bookList.get(cnt).getTitle() + " " + bookList.get(cnt).getRating());
}
}
}
Is there a way to alter the code in the algorithm class to display the bookList sorted by Title?
You can't use < directly on two Strings, but you can use compareTo.
if (bookList.get(in).getTitle().compareTo(bookList.get(in + 1).getTitle()) < 0) { ...
If s1 and s2 are strings, s1.compareTo(s2) returns a negative value if s1 is lexicographically less than s2, a positive value if s1 is greater, and 0 if the two strings are equal.
For your class Book make it implement Comparable. You'll have to create some methods in your Book class in order to compile. Implement them according to the Java API then you can just throw them into a TreeSet<Book> and it will be sorted.
Edit:
I realize this doesn't directly answer your question, but it would be a more Java solution.
I think change your code :
if (bookList.get(in).getRating() < bookList.get(in + 1).getRating())
to
if (bookList.get(in).getTitle().compareTo(bookList.get(in + 1).getTitle()<0)
would be OK.
But,why dont you implement different Comparators and use it like this: Collections.sort(bookList,yourComparator)
something like this:
public static void main(String[] args) {
List<Book> bookList = new ArrayList<Book>();
Collections.sort(bookList, new TitleComparator());
Collections.sort(bookList, new RatingComparator());
}
static class TitleComparator implements Comparator<Book> {
#Override
public int compare(Book o1, Book o2) {
return o1.getTitle().compareTo(o2.getTitle());
}
}
static class RatingComparator implements Comparator<Book> {
#Override
public int compare(Book o1, Book o2) {
return o1.getRating() - o2.getRating();
}
}
To implement bubble-sort for any type of Object, in that case Book, implements in your object class the interface Comparable and override the methode compareTo to define your desired handling.
The method should return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
As stated in the javadoc :
http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html
In your case, the compareto method is already implemented in the String class so you can directly use it on the book's title.
Your validation would then look like this :
if (bookList.get(in).getTitle().compareTo(bookList.get(in + 1).getTitle()) < 0)

compareTo method for ordering integers

I'm having a difficult time creating a compareTo() method for my program. My program reads 5 pairs of String/Integers from the commandline. They will represent names and ages for a Person object.
For instance my commandline arguments are: Asia 19 Java 20 Html 25 CSS 18 Ruby 10
My goal is to display them in a dialog box rearranged from smallest to biggest number.
*The problem I need help with is with my compareTo() method. I'm kinda of stuck at this point, as I just don't think I understand the concept of using this method. If someone can give me a informative explanation that would be awesome!
My code:
// To display dialog box(s)
import javax.swing.JOptionPane;
//An interface used to compare two objects.
import java.lang.Comparable;
public class searchSort{
public static void main(String[] args){
if (args.length != 10){
System.out.println("Please enter 5 String/Intger pairs " +
"on the commandline");
}
else{
int age1 = new Integer(0);
int age2 = new Integer(0);
int age3 = new Integer(0);
int age4 = new Integer(0);
int age5 = new Integer(0);
try{
age1 = Integer.parseInt(args[1]);
age2 = Integer.parseInt(args[3]);
age3 = Integer.parseInt(args[5]);
age4 = Integer.parseInt(args[7]);
age5 = Integer.parseInt(args[9]);
}
catch (NumberFormatException exception) {
System.out.println("Error: Commandline arguments 2,4,6,8,10 must be a positive integer.");
System.exit(0); // end program
}
Person[] arr = new Person[5];
arr[0] = new Person(args[0], age1);
arr[1] = new Person(args[2], age2);
arr[2] = new Person(args[4], age3);
arr[3] = new Person(args[6], age4);
arr[4] = new Person(args[8], age5);
JOptionPane.showMessageDialog(null, arr[0]+ "\n" +arr[1]+ "\n"+arr[2]+ "\n"+
arr[3] + "\n" + arr[4]);
//
}
}
}
class Person implements Comparable{
// Data Fields
protected String name;
protected int age;
// Constructor
public Person(String n1, int a1){
name = n1;
age = a1;
}
//toString() method
public String toString(){
String output = name + " is " + age + " years old.";
return output;
}
//getAge() method
public int getAge(){
return age;
}
// compareTo() method
public int compareTo(Object object) throws ClassCastException{
int person1 = this.getAge();
int person2 = object.getAge();
int result = this.getAge() - object.getAge();
return result;
}
}
Your code won't compile, because you're using an Object as a Person. You need to cast it:
public int compareTo(Object object) throws ClassCastException{
return age - ((Person)object).age;
}
And you only need one line, and you can access fields directly.
The contract for the compareTo(Object obj) method demands that you return:
n < 0 if this is to be considered less than obj
0 if this is equal to obj
n > 0 if this is greater than obj
This way you can define sorting behavior for your class.
Arrays.sort(people);
Note that you can sort your objects backwards by just inverting the sign of the return value.
As a side note, some sorting methods allow you to pass a Comparator along with the collection you want to sort, which enables you to define a different sort criterion other than the default one.
Arrays.sort(people, new Comparator<Person>() { ... });
What the Comparable enables is for you to sort Person objects when they're in a container object like a List or an Array.
I suggest looking at the Arrays and Collections classes for how to do this.

Comparator for sorting an object arraylist by float parameter

How can i create a comparator to be able to sort an arraylist by a float parameter?
Imagine i have an arraylist of objects that has something like this:
ID=7 TFIDF=0.12654299 PR=25238.0
ID=4 TFIDF=0.12654299 PR=3638.0
ID=4 TFIDF=0.12654299 PR=3638.0
ID=4 TFIDF=0.12654299 PR=3638.0
ID=3 TFIDF=0.56442446 PR=14558.0
ID=1 TFIDF=0.0083091585 PR=3953.0
I want to sort the array by TFIDF values.. As far as i know i can only sort them by integer.. Thus, im comparing zeros.
So far i have this:
Collections.sort(Contents_To_Show, new Comparator<ContentToShow>() {
public int compare(ContentToShow o1, ContentToShow o2) {
return (int) (o1.GetPR() - o2.GetPR());
}
});
But. Again, it compares me only the integer part. How can i compare the entire value?
Please help.
Thanks
Followup to Pedro's followup. If you want to sort by TFIDF, then by PR,
int result = Float.compare(o1.getTFIDF(), o2.getTFIDF());
if (result == 0)
result = Float.compare(o1.getPR(), o2.getPR());
return result;
Ok, from your comment the issue that you have is that you are using the substraction code to your comparator, but as the float values difference is less than 1 (absolute value), casting to int always rounds to 0.
Use a more generic form, with if
public int compare(ContentToShow o1, ContentToShow o2) {
if (o1.getTFIDF() > o2.getTFIDF()) {
return -1;
}
if (o1.getTFIDF() < o2.getTFIDF()) {
return 1;
}
return 0
}
As I said, how do you get the compare result value (as long as it is coherent) is not related to the sorting.
I want to sort the array by TFIDF values..
Then why are you comparing PR values with o1.GetPR()
public int compare(ContentToShow o1, ContentToShow o2) {
return (int) (o1.GetPR() - o2.GetPR());
}
Try comparing the TFIDF values in your compare method (but as mentioned casting to int will always round to int value i.e. 0)
return (int) (o1.GetTFIDF() - o2.GetTFIDF());
So you could use
return Float.valueOf(o1.GetTFIDF()).compareTo(Float.valueOf(o2.GetTFIDF()))
In Java 8 with lambda functions is now very simple to compare two float in a object list. I use in this example both lambda functions and functional operations (new features in Java 8). In your main you can try this example. This example arrange people by floats that represent the height :
List<Person> people = Person.createStandardList(); // create a list with 2 standard users
Collections.sort(people, (Person p1, Person p2) -> Float.compare(p1.height_in_meter, p2.height_in_meter));
people.stream().forEach((p) -> { // functional operation
p.printName();
});
This is my class Person
public class Person {
public static List<Person> createStandardList() {
List<Person> people = new ArrayList<>();
Person p = new Person();
p.name = "Administrator";
p.surname = "admin";
p.address = "Via standard 1";
p.age = 26;
p.sex = 'M';
p.height_in_meter = 1.70f;
p.weight_in_kg = 68.50f;
people.add(p);
p = new Person();
p.name = "First";
p.surname = "Creator";
p.address = "Via standard 2";
p.age = 30;
p.sex = 'F';
p.height_in_meter = 1.80f;
p.weight_in_kg = 58.50f;
people.add(p);
p = new Person();
p.name = "Second";
p.surname = "Creator";
p.address = "Via standard 3";
p.age = 20;
p.sex = 'F';
p.height_in_meter = 1.30f;
p.weight_in_kg = 48.50f;
people.add(p);
return people;
}
public String name;
public String surname;
public String address;
public int age;
public char sex;
public float height_in_meter;
public float weight_in_kg;
public String getName() {
return name;
}
public String getSurname() {
return surname;
}
public float getHeight_in_meter() {
return high_in_meter;
}
public float getWeight_in_kg() {
return weight_in_kg;
}
public void printName() {
System.out.println(this.name);
}
}
The output is :
Second
Administrator
First
So I think this example it's easier to understand JAVA 8 features. In Documentation you try a similar example but with strings that use another method. (Oracle official documentation to lambda functions with Collection example)

Comparison of Pojo class properties

I have a class containing two properties:
public class player{
public player(String playerName,int points){
this.playerName=playerName;
this.points=points;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
private String playerName;
private int points;
}
I have arrayList class contains collection of palyer objects.
List palyers=new ArrayList();
players.add(new player("mike",2));
players.add(new player("steve",3));
players.add(new player("jhon",7));
players.add(new player("harry",5);
Here my question is how to display player names with smallest points difference.
Output:
Based on the example code i written:
Mike and steve is the output
THis way comparison should happen:
mike to steve --> 1
mike to jhon--->5
mike to harry-->3
steve to mike -->1
steve to jhon--->5
steve to harry--->3
jhon to mike-->5
jhon to steve-->4
jhon to harry--->2
harry to mike -->3
harry to steve-->2
harry to jhon -->2
Based on above comparison mike and steve should display
Any java API to compare the properties?
Using anonymous inner class, Comparator and Collections.sort():
Collections.sort(palyers, new Comparator(){
public int compare(Object o1, Object o2){
player p1 = (player) o1;
player p2 = (player) o2;
return p1.getPoints().compareTo(p2.getPoints());
}
});.
So you want to know the pair of players whose score has the smallest difference?
I don't think there's an API function for that, although there might be something in the Apache Commons Collections.
Otherwise you'll have to use a nested loop.
int res1 = -1, res2 = -1;
int maxDiff = Integer.MAX_VALUE;
for ( int i = 0; i < players.size( ); i++ )
{
for ( int j = i + 1; j < players.size() ; j++ )
{
int diff = Math.abs( players.get(i).getPoints( ) - players.get(j).getPoints( ) );
if ( diff < maxDiff )
{
maxDiff = diff;
res1 = i;
res2 = j;
}
}
}
System.out.println(players.get(res1).getPlayerName( ) + " and " + players.get(res2).getPlayerName( ));
Obviously, this code needs some work; for example, if two pairs of players have the same difference between them, only the latest pair processed will be reported. You may also want to re-work this piece of code to remove the default values (Note how the System.out.println will crash if your List contains 0 players, for example). I leave these for you to solve. HTH.
Write a Comparator and use it to sort the List by points. You're just comparing Player instances.
Yes, implement Comparable with your player class (please use "Player", uppercase first letter for classes, otherwise it's confusing):
public class Player implements Comparable<Player>
{
....
public int compareTo(Player other)
{
if (this.points == other.points)
return 0;
if (this.points > other.points)
return 1;
return -1;
}
}
Then you can sort the List using Collections.sort(players);

Categories