EDIT: Added some information.
I got an array of Objects. Each object has a name and a value. I need to sort the objects in descending order of those values, and print the names. I saw this easy solution but can't seem to apply it to my problem: http://www.mkyong.com/java/java-object-sorting-example-comparable-and-comparator/
The code compiles with no error but the array is not sorted at all. I know this because I know what the output should be i.e. the output should be something like var364, var200, var65 etc. and what i get is var1, var2, var3 etc.
I tried to strip the code of the irrelevant parts here:
Main class
print(data.preselection());
private void print (UnitRow preselectedUnitRow) {
out.printf("Variables after preselection: \n");
for (int i=0;i<PRESELECTION_LIMIT;i++) {
out.printf("%s, ",preselectedUnitRow.getUnitName(i));
}
}
Dataset (data)
private UnitRow data;
...
public UnitRow preselection() {
UnitRow standardDeviationUnits = new UnitRow(numberOfVariables);
for (int i=0;i<numberOfVariables;i++){
Unit unit = new Unit(1,variableNames[i],calculateStandardDeviation(i));
standardDeviationUnits.add(unit);
}
standardDeviationUnits.sort();
return standardDeviationUnits;
}
UnitRow
import java.util.Arrays;
public class UnitRow {
private Unit[] units;
private int count;
...
public void sort() {
Arrays.sort(units);
}
}
Unit
public class Unit implements Comparable<Unit>{
private NumberRow elements; //just a class with an array of doubles
private String name;
...
#Override
public int compareTo(Unit compareUnit) { //getValue returns a single type double number
int comparison = (int) (compareUnit.getValue(0) - getValue(0));
return comparison;
}
}
I am assuming my implementation of Comparable is wrong. Can you spot the problem?
I say this because I tested as following:
System.out.println(standardDeviationUnits.getValue(0,0));
standardDeviationUnits.sort();
System.out.println(standardDeviationUnits.getValue(0,0));
And the exact same value is returned.
It looks like reverse order
public int compareTo(Unit compareUnit) {
if (getValue(0) < compareUnit.getValue(0)) return 1;
else if (getValue(0) > compareUnit.getValue(0)) return -1;
return 0;
}
Try this.
Also note that in your compareTo, you unnecessarily wrote return 2; and wrote 3 if instead of 1 if-else.
If you are trying to sort as per names:
return compareUnit.name.compareTo(name);
else I have no idea what attribute your getValue(0) returns to you but still if you are trying to sort as per getValue(0):
return compareUnit.getValue(0)-getValue(0);
Related
I have list which contains a property class object, In the list i have 3 status
not_paid
paid
part_paid
I want to sort my list below mentioned order.
First - not_paid
second- part_paid
third -paid
How can I sort my list using Comparator class.?
public static Comparator<OrderHistoryItemData> COMPARE_BY_PAYMENT = new Comparator<OrderHistoryItemData>() {
public int compare(OrderHistoryItemData one, OrderHistoryItemData other) {
String p1 = one.getAttributes().getFieldPaymentStatus();
String p2 = other.getAttributes().getFieldPaymentStatus();
if (p1.equals(p2)) {
return 0;
}
if (p1.equals("not_paid") && (p2.equals("part_paid") || p2.equals("not_paid"))) {
return -1;
}
if (p1.equals("not_paid") && p2.equals("not_paid")) {
return -1;
}
return 1;
}
};
This is my Code. i am getting below order using this code.
paid-->not_paid-->part_paid
This is my Update Code. I got my result.
public static Comparator<OrderHistoryItemData> COMPARE_BY_PAYMENT = new Comparator<OrderHistoryItemData>() {
public int compare(OrderHistoryItemData one, OrderHistoryItemData other) {
String p1 = one.getAttributes().getFieldPaymentStatus();
String p2 = other.getAttributes().getFieldPaymentStatus();
if (p1.equals(p2)) {
return 0;
}
if (p1.equals("not_paid") && (p2.equals("part_paid") || p2.equals("paid"))) {
return -1;
}
if (p1.equals("part_paid") && p2.equals("paid")) {
return -1;
}
return 1;
}
};
To avoid complex comparator, I encourage you to export your statuses to an enum. (Plus this will work if you will add more statuses in the future, without the need to change logic in your comparator):
enum PaymentStatus { // Write them in order you want to be sorted
NOT_PAID,
PART_PAID,
PAID
}
Then sorting will be as simple as :
list.sort(Comparator.comparing(item ->item.getAttributes().getFieldPaymentStatus()));
What you can do is first mapping the strings to integers in the desired order, and then simply subtracting them from eachother.
private static Comparator<Payments> comparator = new Comparator<Payments>() {
// Use this mapping function to map the statuses to ints.
// The lowest number comes first
private int map(String str) {
switch (str) {
case "not_paid":
return 0;
case "part_paid":
return 1;
case "paid":
return 2;
default:
return 3;
}
}
// Alternatively, you can use the Map interface to define the sorting
// order.
#Override
public int compare(Payments o1, Payments o2) {
return map(o1.status) - map(o2.status);
}
};
I suggest – Schidu Luca already mentioned it in his answer – that you use enums to define a fixed set of known values, like payment statuses. This provides compile-time safety.
Note: I wouldn't, however, suggest to bind the enum declaration order to the sorting order.
Basically, I have 2 classes. One of them has a private member ArrayList(Objects from the other class) and every object from the list has a private field points. I have a method to iterate through the list and get the sum of all points. So I just want to compare list1 > list2 by their summed points. But I'm failing to achieve that - my compareTo() returns always 0.
Here is a short code example of this.
public class StudentsGroup implements IFile, Comparable {
private List<Student> studentsList = new ArrayList<Student>();
public int compareTo(Object o) {
if(StudentsGroup.getTotalPoints(studentsList) < ((StudentsGroup)o).getTotalPoints(studentsList))
return 1;
else if(StudentsGroup.getTotalPoints(studentsList) > ((StudentsGroup)o).getTotalPoints(studentsList))
return -1;
else
return 0;
}
public static int getTotalPoints(List<Student> studentsList1) {
int totalPoints = 0;
for(Student o : studentsList1) {
totalPoints += o.getStudentPoints();
}
return totalPoints;
}
}
The method
if(
StudentsGroup.getTotalPoints(studentsList) <
((StudentsGroup)o).getTotalPoints(studentsList))
You are passing the same studentsList to both sides of the calculation.
The "other group" o is not used at all.
It may look like o is used, but getTotalPoints is a static method and it does not matter what instance you call it on. The compiler will give you a warning about this, too. Do not ignore compiler warnings.
Immediate fix would be to change the code to
if( getTotalPoints(studentsList) < getTotalPoints((StudentsGroup)o).studentsList)
But you should probably change that getTotalPoints method from public static to public (not-static). Instead of the list being passed as a parameter, it can then just use this.studentsList internally.
if (this.getTotalPoints() < ((StudentsGroup)o).getTotalPoints())
In that case I would check the values are not both the same (or both 0)
public class StudentsGroup implements IFile, Comparable<StudentsGroup> {
private List<Student> studentsList = new ArrayList<Student>();
public int compareTo(StudentsGroup sg) {
return Integer.compare(getTotalPoints(), sg.getTotalPoints());
}
public int getTotalPoints() {
return Math.toIntExact(studentsList.stream()
.mapToInt(Student::getStudentPoints).sum());
}
}
By simplifying the code you are less likely to mix up a static method with an instance method (StudentsGroup)o).getTotalPoints(studentsList) just calls StudentsGroup.getTotalPoints(studentsList) as you don't have an instance method.
i am trying to sort an array of strings which are terms of a polynomial. every position is 1 term of the polynomial as a string, and signed approapriately, however i want to sort them in order by the power.
eg
+3x^5
+5
-8x
-4x^2
how i have approached this is by creating a second array storing just the power, and i want to sort them both based off this array. ie
for (int i=0; i<sortArray.length; i++) {
if (sortArray[i].indexOf("^")!= -1)
sortArrayDegree[i] = Integer.parseInt((sortArray[i].
substring(sortArray[i].indexOf("^") + 1, sortArray[i].length())));
else if (sortArray[i].indexOf("x")!= -1)
sortArrayDegree[i]=1;
else
sortArrayDegree[i]=0;
}
however i am not sure how to link the two, so any changes to the second happen to the first
currently that means the second array looks like this
5
0
1
2
i thought i could make a new array and store this as the second column(clash of data types), but that still leaves the sorting problem
I'm not sure that the way you want achieve this is the wisest way, but this is how you could do it:
Create a class of both the power and the number of the polynomial member. Make that class Comparable, then put it in one array and the sort method will use the comparable method you have overridden from the Comparable interface.
public class PolynomialMember implements Comparable<PolynomialMember> {
public int power; // public for brevity, but should be private with getters and setters
public String number; // public for brevity, but should be private with getters and setters
public PolynomialMember(String number, int power) {
this.number = number;
this.power = power;
}
#Override
public int compareTo(PolynomialMember o) {
return Integer.compare(this.power, o.power);
}
// optional: override for pretty printing
#Override
public String toString() {
if(!number.equals("0")) {
if(number.charAt(0) == '-') {
return number + "x^" + power;
} else {
return "+" + number + "x^" + power;
}
} else {
return "";
}
}
}
this way you don't need two arrays, and you certainly shouldn't "link" two arrays.
You can use this class like this:
public static void main(String[] args) {
List<PolynomialMember> polynom = new ArrayList<PolynomialMember>();
polynom.add(new PolynomialMember("-5", 3));
polynom.add(new PolynomialMember("7", 1));
polynom.add(new PolynomialMember("4", 0));
polynom.add(new PolynomialMember("8", 2));
for(PolynomialMember pm : polynom) {
System.out.print(pm + " ");
// prints: -5x^3 +7x^1 +4x^0 +8x^2
}
System.out.println();
Collections.sort(polynom); //this is where the magic happens.
for(PolynomialMember pm : polynom) {
System.out.print(pm + " ");
// prints: +4x^0 +7x^1 +8x^2 -5x^3
}
}
If I understand correctly, which I'm really not sure, you want to bind the data of 2 arrays containing value types\immutables. The easiest way i know to bind data from 2 arrays is to create a class containing both of them as private members and exposing public methods to control them. in these methods you could implement the logic that defines the relationship between them.
I have a string array that is similar to:
[module-src1, module-src2, module-src3, ..., source1, source2, source3, ...]
I want to reorder this array to be:
[source1, source2, source3, ..., module-src1, module-src2, module-src3, ...]
What would be the most efficient way to do this in Java?
I thought about having 2 queues to store each, but that seems overly complicated and I am hoping to see if there is a more efficient way of doing this.
The best way I can think of doing it is by having your own class like
public class Source implements Comparable<Source> {
private String name;
public Source(String name){
this.name = name;
}
public String getName(){
return name;
}
#Override
public String toString(){
return name;
}
#Override
public int compareTo(Source another) {
//do whatever sorting you want here
//for example:
if(name.subString(0,5).equalsIgnoreCase("module") &&
another.getName().subString(0,5).equalsIgnoreCase("module"){
//both start with module, so alphabetize
return name.compareTo(another.getName());
} else if(name.subString(0,5).equalsIgnoreCase("module") &&
!another.getName().subString(0,5).equalsIgnoreCase("module"){
//only this one starts with "module", the other one comes first
return -1;
}
...
}
}
hopefully you get the gist with that.
Once you have all those objects in an ArrayList or something, just do Collections.sort(myArray) and it should sort it in the order you want
You have to make some assumptions about your input (that is, you have to assume that all strings in your array are formatted either "module-"- or "source"-prefixed). If that's the case, then you could do something like this:
public static void main(String[] args){
String[] strings = new String[]{"module-src1","module-src2",
"module-src3","source1","source2","source3"};
Arrays.sort(strings,new ModSrcComparator());
for(String s : strings) System.out.print(s+" ");
System.out.println();
}
private static class ModSrcComparator implements Comparator<String>{
#Override
public int compare(String s1, String s2) {
if(!s1.contains("-") && s2.contains("-")) return -1;
else if(s1.contains("-") && !s2.contains("-")) return 1;
return s1.compareTo(s2);
}
}
If you want to keep a String array with a minimal number of lines of code:
List<String> myList = new ArrayList<>(Arrays.asList(myArray))
Collections.sort(myList);
myArray = myList.toArray(new String[0]);
I'd suggest using a List instead of an array, which brings this down to a single line of code:
Collections.sort(myList);
I have an array of phonebook elements and I'm trying to sort them according to lexicographical order using comparable sort. But it all messes up. Please help. Thanks in advance
It will also help to describe about sort function in java a little bit!
Here is the code:
package myphonebook;
import javax.swing.*;
import java.util.Arrays;
import java.util.Comparator;
public class MyPhoneBook implements Comparator<MyPhoneBook>{
private String name,email,number;
MyPhoneBook()
{
}
public void input()
{
name = (JOptionPane.showInputDialog("Enter Name:\n")).toString();
number = JOptionPane.showInputDialog("Enter Number:\n").toString();
email = JOptionPane.showInputDialog("Enter email:\n").toString();
}
public void print()
{
JOptionPane.showMessageDialog(null, "Name: " + name+ "\n" + "Phone: " +number +"\n" + "Email: " + email);
}
public static void main(String[] args) {
MyPhoneBook a[] = new MyPhoneBook[300];
MyPhoneBook b = new MyPhoneBook();
//final Integer[] sorted = ArrayUtils.toObject(MyPhoneBook);
int i,n;
n = Integer.parseInt(JOptionPane.showInputDi… total number:\n"));
for(i=0;i<n;i++)
{
a[i] = new MyPhoneBook();
a[i].input();
}
Arrays.sort(a);
for(i=0;i<n;i++)
{
a[i].print();
}
}
#Override
public int compare(MyPhoneBook o1, MyPhoneBook o2) {
return o1.number.compareTo(o2.number);
}
public int compareTo(MyPhoneBook o) {
if(this.name.equals(o.name)) return this.number.compareTo(o.number);
if(this.number.equals(o.number)) return this.email.compareTo(o.email);
if(this.email.equals(o.email)) return this.name.compareTo(o.name);
return 0;
}
}
There are several problems here: the first is that your comparison is not actually lexicographic. For example, when the names are equal, you completely ignore the email address in your comparison logic. The second problem is that you fail to specify the comparator as a parameter to Arrays.sort().
First problem: fix comparison logic
If you can use third-party libraries in your code, then a really neat and simple way to handle this is using the ComparisonChain class from the Guava libraries (Google's core Java libraries that are opensource):
public int compareTo(MyPhoneBook o) {
return ComparisonChain
.start()
.compare(name, o.name)
.compare(email, o.email)
.compare(number, o.number)
.result();
}
Assuming you can't do that, however, here's the right way to do it:
public int compareTo(MyPhoneBook o) {
int nameComparison = name.compareTo(o.name);
if (nameComparison != 0) {
return nameComparison;
}
int emailComparison = email.compareTo(o.email);
if (emailComparison != 0) {
return emailComparison;
}
return number.compareTo(o.number);
}
Second problem: invoke Arrays.sort() with the comparator
Instead of your current call to Arrays.sort(), use:
Arrays.sort(a, new PhoneBookComparator());
And define PhoneBookComparator as a separate Comparator class.
Just use String#compareTo, it compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings.
public class MyPhoneBook implements Comparable<MyPhoneBook>{
#Override
public int compareTo(MyPhoneBook o) {
int returnValue =0;
if(o!=null){
returnvalue = this.name.compareTo(o.name);
if(returnValue==0){
returnValue = this.number.compareTo(o.number);
if(returnValue==0){
returnValue = this.email.compareTo(o.email);
}
}
}
return returnValue;
}
}
When running the code as you posted it it comes to a
Exception in thread "main" java.lang.ClassCastException: ...
MyPhoneBook cannot be cast to java.lang.Comparable
This is because you call
Arrays.sort(a);
Arrays.html#sort expects the Objects contained in the array to be implementing the interface Comparable. Your class is implmenting Comparator though.
You should change your class declaration to one of the following
public class MyPhoneBook implements Comparable<MyPhoneBook> {
and just remove
#Override
public int compare(MyPhoneBook o1, MyPhoneBook o2) {
return o1.number.compareTo(o2.number);
}
Or
public class MyPhoneBook {
and the call of sort to
Arrays.sort(a, new Comparator<MyPhoneBook>() {
#Override
public int compare(MyPhoneBook o1, MyPhoneBook o2) {
// TODO implment here your comapre logic
return o1.number.compareTo(o2.number);
}
});
After you have fixed that you'll get NullPointerException, againt because of the line
Arrays.sort(a);
This is because you pass an array of the length 300 and you do not necessarily have to put all 300 element in it since you ask for total number
you should be using
Arrays.sort(a, 0, n);
This sorts only the range witch have data. See the javadoc.