I have an ArrayList<ArrayList<String>> that is a list of couple of values:
John, 12.3
Marcus, 35.0
Sue, 11.4
How to sort the list by amount?
If in this case there is a better way than using an ArrayList of an ArrayList, please tell me and tell me then how to sort it. Thank you.
Instead I will recommend you to use a class and use class like comparable or comparator to sort.
Something like this:
class Person implements Comparable<Person> {
String name;
double amount;
Person(String n, double d) {
name = n;
amount = d;
}
public int compareTo(Person other) {
if (amount != other.amount)
return Double.compare(amount, other.amount);
return name.compareTo(other.name);
}
}
and this is easy to implement and understand.
Use a Comparator:
A comparison function, which imposes a total ordering on some
collection of objects. Comparators can be passed to a sort method
(such as Collections.sort or Arrays.sort) to allow precise control
over the sort order. Comparators can also be used to control the order
of certain data structures (such as sorted sets or sorted maps), or to
provide an ordering for collections of objects that don't have a
natural ordering.
It'd be great if you could add more information about why you are using those values then I am sure a better approach can be suggested.
I solved with this:
Collections.sort(data, new Comparator<ArrayList<String>>() {
#Override
public int compare(ArrayList<String> one, ArrayList<String> two) {
// Replacements for using Double.parseDouble(string) later
String value1 = one.get(1).replace(",", ".");
String value2 = two.get(1).replace(",", ".");
if (Double.parseDouble(value1) < Double.parseDouble(value2))
return -1;
else if (Double.parseDouble(value1) > Double.parseDouble(distanza2))
return 1;
else
return 0;
}
});
Related
This question already has answers here:
Sorting an ArrayList of objects using a custom sorting order
(12 answers)
Closed 8 years ago.
I want to sort this list of Emp objects in ascending order based on the marks field.
List<Emp> emp= new ArrayList<Emp>();
public class Emp implements Serializable {
private String empname;
private String section;
private int empId;
private int marks;
...
You need to write a comparator, otherwise the Sort method assumes which fields you want use when sorting.
Collections.sort(emp, new Comparator<Emp>() { public int compare(Emp one, Emp two) {
return one.marks.compareTo(two.marks);
});
In my example i treated the field marks as public, replace one.marks with a getter if you so choose.
Also since you're using ints which do not have a compareTo, do like so:
Collections.sort(list, new Comparator<Emp>() {
public int compare(Emp one, Emp two) {
int cmp = one.getMarks() > two.getMarks() ? +1 : one.getMarks() < two.getMarks() ? -1 : 0;
return cmp;
}
});
You can use a comparator object to sort.
Collections.sort();
does the sorting.
This will work with your List. The method to be used is compareTo.
if (list.size() > 0) {
Collections.sort(list, new Comparator<Emp>() {
#Override
public int compare(final Emp object1, final Emp object2) {
return object1.getMarks().compareTo(object2.getMarks());
}
} );
}
There are two main ways of supporting object comparisons in Java.
You can have your class implement the Comparable interface, which is acceptable when your objects have a natural ordering that you're relying on (for example, alphabetical ordering for strings). This requires classes to implement a compareTo method which defines the comparison rule between instances.
The standard alternative is to instantiate a Comparator for your class, and specify the comparison rule in a compare method.
In your case, the latter option seems more appropriate. The mechanics of the compare method are fairly simple: it takes two instances of your class, returns a negative value if the first is "less than" the second, a positive number if it is "greater", and 0 if they are "equal". For integer-based comparisons, like comparing by marks, the quick trick is to return the difference of the numbers.
Once you have your Comparator defined, sorting is as simple as invoking the Collections.sort method, opting for the method signature which takes a List and a specified Comparator.
List<Emp> emps = new ArrayList<Emp>();
// populate list...
Comparator<Emp> empComparator = new Comparator<Emp>() {
public int compare(Emp e1, Emp e2) {
return e2.getMarks() - e2.getMarks();
}
};
Collections.sort(emps, empComparator);
I have 2 arrays:
private String[] placeName;
private Double[] miles;
The data in them look like this:
placeName = {"home", "away", "here"};
miles = {111, 11, 3};
The position of the values match to each other. ie home = 111 and away = 11
I need to sort these arrays together so I don't lose how they are matched by the the number- lowest to highest. What is the best way to accomplish this? Do I need to combine the arrays first?
Since the two values are so tightly coupled together I would actually write a custom class to contain the information and then sort those classes instead of playing around with raw arrays. Doing so would leave you open to many possible bugs down the line.
This allows for much better control, data encapsulation and future expansion of what methods or data your class may contain.
public class MyDistance implements Comparable<MyDistance> {
private String placename;
private double mileage;
public MyDistance(String placename, double milage) {
this.placename = placename;
this.milage = milage;
}
public String getPlacename() {
return this.placename;
}
public double getMilage() {
return this.milage;
}
#Override
public int compareTo(MyDistance anotherDistance)
{
return milage.compareTo(anotherDistance.getMilage());
}
}
If you want more flexibility in your sort then instead of having your MyDistance class implement Comparable you can write a custom Comparator<MyDistance> class:
public class DistanceComparator extends Comparator<MyDistance> {
#Override
public int compare(MyDistance dist1, MyDistance dist2) {
return dist1.getMilage().compareTo(dist2.getMilage());
}
}
You can use this Comparator to sort using Collections:
List<MyDistance> distanceList = getDistanceListSomehow();
Collections.sort(distanceList, new DistanceComparator());
You are not restricted to a List, I just used it for explanatory purposes. You should look at the full range of Java Collections types to best choose one that suits your purposes. As a suggestion though, the ArrayList type is easy to use and retains order like you would want.
One way is to create a TreeMap. Assuming you are sorting by miles.
TreeMap tm = new TreeMap<Double, String>();
for (int i=0; i<miles.length; i++) {
tm.put(miles[i], placeName[i]);
}
// tm is already sorted - iterate over it...
NOTE: IF you have places with the same exact distance in miles this will not work. e.g. if you had a "work" that was 11 miles, just like "away", this won't work. You'd probably want some form of MultiMap for that...
Maybe put the arrays in a TreeMap and sort it
SortedMap<Double,String> map = new TreeMap<>();
map.put(111,"home");
map.put(11,"away");
map.put(3,"here");
The elemtns are inserted sorted by their key
I have a simple class that contains a string (name) and an integer (age). The objects, that shall be stored in the collection, must not have double name values and shall be sorted according to descending age.
The first code example removes all double names, but doesn't contain a second ordering criterion:
public int compare(Person p1, Person p2) {
int reVal = 1;
if(p1.getName().compareTo(p2.getName()) != 0){
reVal = 1;
}
else {
reVal = 0;
}
return reVal;
}
The next example comparator shall order the rest set of the objects, that doesn't contain any double names:
public int compare(Person p1, Person p2) {
boolean ageGt = (p1.getAge() > p2.getAge());
int reVal = 1;
if(p1.getName().compareTo(p2.getName()) != 0){
if(scoreGt)
reVal = -1;
else
reVal = 1;
}
else {
reVal = 0;
}
return reVal;
}
The second comparator orders the objects according their age values correctly, but it allows double names, which I don't understand, because the outer if-statement already checked if the names of both objects are equal. Why does that happen?
You have a fundamental problem here: you want at the same time to test for unicity and to order entries. There is no builtin collection which will check at the same time that entries are equal and that their comparison is 0.
For instance, two Set implementations are HashSet and TreeSet:
HashSet uses Object's .equals()/.hashCode() to test for equality;
TreeSet uses a Comparator (or the objects' Comparable capability if they implement it) to test for equality.
This is not quite the same thing. In fact, with one particular JDK class, that is, BigDecimal, this can get quite surprising:
final BigDecimal one = new BigDecimal("1");
final BigDecimal oneDotZero = new BigDecimal("1.0");
final Set<BigDecimal> hashSet = new HashSet<>();
// BigDecimal implements Comparable of itself, so we can use that
final Set<BigDecimal> treeSet = new TreeSet<>();
hashSet.add(one);
hashSet.add(oneDotZero);
// hashSet's size is 2: one.equals(oneDotZero) == false
treeSet.add(one);
treeSet.add(oneDotZero);
// treeSet's size is... 1! one.compareTo(oneDotZero) == 0
You cannot both have your cake and eat it. Here, you want to test unicity according to the name and comparison according to the age, you must use a Map.
As to obtain a sorted list of persons, you will have to do a copy of this map's .values() as a list and use Collections.sort(). If you use Guava, this latter part is as simple as Ordering.natural().sortedCopy(theMap.values()), provided your values implement Comparable.
I am having trouble solving a particular problem in Java (which I did not find by search). I do not know how to create a nested lists of objects - with a different type of object/primitive type at the end. For example:
*Note: only an example. I am actually doing this below with something other than Employee, but it serves as simple example.
I have an array of an object Employee. It contains information on the Employee.
public class Employee {
int age
int salary
int yearsWorking
public Employee () {
// constructor...
}
// Accessors
}
What I need to do is organize the Employees by quantiles/percentiles. I have done so by the following:
import org.apache.commons.math.stat.descriptive.rank.Percentile;
public class EmployeeSort {
public void main(String args[]) {
Percentile p = new Percentile();
Employee[] employeeArray = new Employee[100];
// filled employeeArray
double[] ageArray = new double[100];
// filled ageArray with ages from employeeArray
int q = 25; // Percentile cutoff
for (int i = 1; i*q < 100; i++) {
// assign percentile cutoff to some array to contain the values
}
}
}
Now, the problem I have is that I need to organize the Employees first by the percentiles of age, then percentiles of yearsWorking, and finally by percentiles of salary. My Java knowledge is inadequate right now to solve this problem, but the project I was handed was in Java. I am primarily a python guy, so this problem would have been a lot easier in that language. No such luck.
Edit:
So I notice some confusion on whether I need ordering, and some people suggesting use of Comparator. I use Comparator because percentiles requires an ordered list. The problem I am having is how to store the binning of the Employee into their appropriate percentile. To clarify, I need the Employee object binned together into their appropriate percentile by age. Then, within that bin of age, I need to bin all those Employee objects within percentiles for Employee.yearsWorking. Following that, within a given percentile bin of yearsWorking which is within a given percentile bin of Employee.age, I need to create percentile bins of Employee.salary.
You should use ArrayList
in place of Arrays.
ArrayList<Employee> employeeList= new ArrayList<Employee>();
for (int i = 0, i <= employeeArray.length; i++)
employeeList.add(employeeArray[i]);
Now write down custom Comparator
public class EmployeeComparatorByAge<Employee>
{
public int compare(Object o1, Object o2)
{
if (o1 != null && o2!= null && o1 instanceof Employee && o2 instanceof Employee )
return ((Employee)o1).age - ((Employee)o2).age;
else
return -1;
}
}
Similarly you can write for other comparisions.
To sort them now, use:
Collections.sort(employeeList, new EmployeeComparatorByAge<Employee>());
This will solve your problem.
Check out java.util.Comparator<T> (the T in this case would be your Employee type)
You can create different Comparators and use Collections.sortList or Arrays.sort(...) (these methods are pseudo methods - look up the exact versions from the docs)
Instead of an array use an ArrayList to hold your Employees. You can then use Collections.sort() to sort that list. There are two versions of sort(), one of which takes a Comparator that will allow you to sort in your desired order.
You might want to read this link to understand Object Ordering in Java
The next thing that you want to do is use an ArrayList and add all your employees in this. You would then want to do something like this:
ArrayList<Employee> employeeList= new ArrayList<Employee>();
/**
* Add your employee objects to the list
*/
Collections.sort(contacts, new Comparator<Employee>() {
public int compare(Employee emp1, Employee emp2) {
int returnValue;
/**
* Your comparison logic
*/
return returnValue;
}
});
I hope this helps!
Use Arrays.sort() with different Comparator implementations as noted above. Keep in mind that this method (as well as Collections.sort()) operate on the data in place. So if you need to keep getting at different views of the data, you may want to duplicate the array and sort it different ways, and hold onto each view.
This would be more efficient (CPU-wise) than constantly re-sorting the array.
As the title suggests, I have a list consisting of pairs of integers (int ai and int bi). I want to sort this list based on only upon int a, while preserving the pairwise relationship. I was wondering if there was an efficient way to do this with some of the standard libraries Java has. Thanks in advance!
Edit:
My exact implementation is an ArrayList<ArrayList<Integer>> in which each ArrayList<Integer> has exactly two integers (ai and bi). Sorry for any confusion.
Use the Collections sort() or Arrays sort() method which takes a Comparator and use a custom comparator which only inspects the first integer in the pair.
Something like this (roughly, depending on your exact types):
Collections.sort(myList, new Comparator<IntegerPair>() {
#Override public int compare(IntegerPair x, IntegerPair y) {
return x.first - y.first;
}
});
Since the sorting algorithms are stable (per the Javadocs) your list will be sorted per your description.
Implement http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html for your integer pairs and use sort() from http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html
I would recommend to create a class that represents integer pair. This class should implement Comparable. The use sort() to sort it.
It may be a little safer to use the already-defined Integer compare:
Collections.sort(myList, new Comparator<IntegerPair>() {
#Override public int compare(IntegerPair x, IntegerPair y) {
return Integer.compare(x.first, y.first);
}
});