Hi I need any method or explanation on how we can order multiple column values in java.
The output should be similar to the multiple column order output in MySQL.
for clarification please check the below link
http://www.dynamicdrive.com/forums/showthread.php?19797-ORDER-BY-Multiple-Columns
Let's say your object looks like this:
public DataObject {
public String name;
public int age;
public String hairColour;
}
Let's say you want to sort them based on age, then hair colour, then name. You could create a comparator as follows:
public DataObjectComparator extends Comparator<DataObject> {
public int compare(DataObject o1, DataObject o2) {
// if the age is the same
if(o1.age == o2.age) {
// if the hair colour is the same
if(o1.hairColour.compareTo(o2.hairColour) == 0) {
// return the name comparison
return o1.name.compareTo(o2.name);
} else { // else return the hair colour comparison
return o1.hairColour.compareTo(o2.hairColour);
}
} else { // else return the age comparison
return o1 < o2 ? -1 : 1;
}
}
}
You can sort arraylist for multiple properties using below sample comparator.
public class CustomeClass implements Comparator<CustomeObject> {
public int compare(CustomeObject o1, CustomeObject o2) {
int value1 = o1.prop1.compareTo(o2.prop1);
if (value1 == 0) {
int value2 = o1.prop2.compareTo(o2.prop2);
if (value2 == 0) {
return o1.prop3.compareTo(o2.prop3);
} else {
return value2;
}
return value1;
}
}
Basically it continues comparing each successive attribute of your class whenever the compared attributes so far are equal (== 0).
Related
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.
I want to sort a list of objects by one of nullable fields.
In order to avoid NullPointerexception I use Comparator.nullsLast. But the exception still occurs:
public class Test {
public static void main(String[] args) {
List<Bean> l = new ArrayList<>();
for (int i=0;i<5;i++) {
Bean b = new Bean("name_"+i,i);
l.add(b);
}
l.get(2).setVal(null);
System.out.println(l);
Collections.sort(l, Comparator.nullsLast(Comparator.comparing(Bean::getVal)));
System.out.println(l);
}
static class Bean{
String name;
Integer val;
// omit getters & setters & constructor
}
}
How can I sort this kind of list?
You should use Comparator.nullsLast twice:
list.sort(nullsLast(comparing(Bean::getVal, nullsLast(naturalOrder()))));
First nullsLast will handle the cases when the Bean objects are null.
Second nullsLast will handle the cases when the return value of Bean::getVal is null.
In case you're sure there aren't any null values in your list then you can omit the first nullsLast (as noted by #Holger) :
list.sort(comparing(Bean::getVal, nullsLast(naturalOrder())));
You can possibly use :
Collections.sort(l, Comparator.comparing(Bean::getVal,
Comparator.nullsLast(Comparator.naturalOrder())));
You can review this example
#Override
public int compare(Example o1, Example o2) {
if (o1 == null && o2 == null) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return Comparator.comparing(Example::getSta,
Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(Example::getId,
Comparator.nullsLast(Comparator.naturalOrder()))
.compare(o1, o2);
}
class Example {
String sta; Long id;}
What can I replace the < and > with because i want to compare string below one is compare int, so got any solution to solve this question and doesnt change the function.
public int compareTo(Object o) {
Patient p = (Patient) o;
if (this.getCategory() < p.getCategory())
return -1;
if (this.getCategory() > p.getCategory())
return 1;
else {
if (this.getTimeArrived().before(p.getTimeArrived()))
return -1;
if (this.getTimeArrived().after(p.getTimeArrived()))
return 1;
}
return 0;
}
How about this? can change the > & < to another solution because i want to compare with string
import java.util.Comparator;
public class PatientComparator implements Comparator<Patient>{
public int compare(Patient p1, Patient p2) {
if (p1.getCategory() < p2.getCategory())
return -1;
if (p1.getCategory() > p2.getCategory())
return 1;
else { if (p1.getTimeArrived().before(p2.getTimeArrived()))
return -1;
if (p1.getTimeArrived().after(p2.getTimeArrived()))
return 1;
}
return 0;
}
}
From the additional information you provided (currently inside an answer) getCategory() returns a String and getTimeArrived() returns a java.util.Date. Your goal seems to be: Compare by "category" and, if equal, then compare by "time arrived".
Both String and Date implement the Comparable interface, so you can do something like this:
public int compareTo(Patient other) {
// This code doesn't handle nulls
int result = getCategory().compareTo(other.getCategory());
if (result == 0) {
result = getTimeArrived().compareTo(other.getTimeArrived());
}
return result;
}
You could also create a Comparator.
Comparator<Patient> c = Comparator.comparing(Patient::getCategory)
.thenComparing(Patient::getArrivedTime);
Also, you are creating a compareTo method without Patient implementing Comparable. You should change it to:
public class Patient implements Comparable<Patient> { /* code */ }
Then override the compareTo method declared in Comparable. This also forces you to use compareTo(Patient) rather than compareTo(Object).
This question already has answers here:
How are Anonymous inner classes used in Java?
(18 answers)
Closed 7 years ago.
Recently I'm trying to get more familiar with the Comparator interface in Java. I have an exercise which is about to sort the ArrayList of strings from the shortest to longest. I used a Comparator of Strings. When searching the net, I found the following solution proposal:
public static Comparator<String> lengthComparator = new Comparator<String>() {
#Override
public int compare(String a, String b) {
if (a.length() == b.length()) {
return a.compareTo(b);
} else {
return (a.length() > b.length() ? 1 : -1);
}
}
};
Then I used it in my code to sort the set:
Collections.sort(set, lengthComparator);
And it worked. What I'd like to ask is the specific way of defining the lengthComparator object here. We create a new object:
new Comparator<String>()
with the default constructor. But then there is a further code with overwritten method in "{}" brackets. Is it a normal way of creating objects? I've never met it before and I'd like to learn more about it. Could you please advise me some referal materials where I can find more informations about it?
Yes this is a common way to create objects, it is called anonymous class.
Comparator is an interface, and you want a class to be instantiated, so you create an object from an anonymous class that implements Comparator.
Anonymous class example
public void sortSetByStringLength(Set set) {
Comparator<String> lengthComparator = new Comparator<String>() {
#Override
public int compare(String a, String b) {
if (a.length() == b.length()) {
return a.compareTo(b);
} else {
return (a.length() > b.length() ? 1 : -1);
}
}
}
Collections.sort(set, lengthComparator);
}
Regular class example
public class LengthComparator implements Comparator<String> {
#Override
public int compare(String a, String b) {
if (a.length() == b.length()) {
return a.compareTo(b);
} else {
return (a.length() > b.length() ? 1 : -1);
}
}
}
And in your program sort a list this way :
public void sortSetByStringLength(Set set) {
Collections.sort(set, new LengthComparator());
}
I'm not sure what's the exact question but as it was already said :
What you have instanciated is an anonymous class. Indeed, as you already know an interface cannot be instanciated.
So, when you do :
new Comparator<String>()
{
#Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
return 0;
}
});
it is like you've created a class called let's say : LengthComparator like this :
public class LengthComparator implements Comparator<String>{
public LengthComparator()
{
}
#Override
public int compare(String o1, String o2) {
int ack = 0;
if(o1 == null && o2 == null){
ack = 0;
}
else if(o1 != null && o2 == null){
// Decide what you should do here !
// returnValue = ???
}
else if(o1 == null && o2 != null){
// Decide here, too !
// returnValue = ???
}
else{
if(o1.length() == o2.length()){
// Sort by order ...
ack = o1.compareTo(o2);
}
else{
ack = o1.length() > o2.length() ? 1 : -1;
}
}
return ack;
}
}
As a personal advice, always check your arguments toward null values as you don't really know what is going to be passed in...
I have an ArrayList in Java :
{"PatMic", "PatientDoc", "Phram", "Patnet", "PatientA"}
All the elements have a number assigned : PatMic = 20, PatientDoc = 30, Phram = 40, Patnet = 50, PatientA = 60.
And my current Comparator :
Comparator<String> comparator = new Comparator<String>() {
#Override
public int compare(final String o1, final String o2) {
final int numbr1 = getElementNumber(); //Returns element's number in a list
final int numbr2 = getElementNumber();
if (numbr1 > numbr2 ) {
return 1;
} else if (numbr1 < numbr2 ) {
return -1;
}
return 0;
}
};
Collections.sort(strings, comparator);
I do not want to change the assigned numbers to each element but would want to move the element PatientA in between PatMic and PatientDoc so the modified list should look like :
{"PatMic", "PatientA" "PatientDoc", "Phram", "Patnet"}
Could someone please suggest how to achieve this? I tried many ways to modify the existing Comparator logic but in vain. Thank you.
You are trying to sort based on some inherent value associated with a String. Therefore, sorting on a String itself is probably not correct. What you probably want to use is either a custom object (implement equals, hashCode and the interface Comparable), or an enum type. This will allow you to change the internal state of these objects explicitly, which will manifest itself naturally when using a Comparator. For example, using a class:
class MyClass implements Comparable
{
private String name;
private int value;
//Constructor
public MyClass(String s, int v)
{
name = s;
value = v;
}
//Getters and setters
//Implement comparing method
}
Then you can use these objects in place of your Strings:
//...
MyClass patMic = new MyClass("PatMic", 20);
// So on..
First, you should give you comparator sufficient knowledge about what it should do. I mean you should have some data available to comparator that says something like "okay, sort them all by associated number except this one - place it right here". "Right here" could be anything that points exact position, I gonna choose "before that element".
So here we go
public void sortWithException(List<String> data, final Map<String, Integer> numbers, final String element, final String next) {
Collections.sort(data, new Comparator<String>() {
#Override
public int compare(String first, String second) {
if (first.equals(element) || second.equals(element)) { //the exception
Integer nextNumber = numbers.get(next);
Integer firstNumber = numbers.get(first);
Integer secondNumber = numbers.get(second);
if (first.equals(element)) {
if (next == null) // placing the exception after ANY element
return 1;
return secondNumber >= nextNumber ? -1 : 1; //placing the element before next and after all next's predecessors
} else { // second.equals(element)
if (next == null)
return -1;
return firstNumber >= nextNumber ? 1 : -1;
}
} else { //normal sort
return numbers.get(first) - numbers.get(second);
}
}
});
}
and call it like sortWithException(data, numbers, "PatientA", "PatientDoc")
Note that i used Map for associated numbers, you should probably use your own method to get those numbers.