Collections.sort(someList, new Comparator<SomeObject>() {
public int compare(final SomeObject object1, final SomeObject object2) {
return (object1.getSomeDate()).compareTo(object2.getSomeDate());
}}
);
Would it give me the objects with latest dates meaning the list will contain the set of objects with latest date to oldest date?
Comparator.comparing
You can pass a method reference to Comparator.comparing.
If you want the objects to be sorted in ascending order based on the date:
someList.sort(Comparator.comparing(SomeObject::getSomeDate));
or
someList.sort(Comparator.comparing(SomeObject::getSomeDate).reversed());
for descending order.
To be sure you can use:
Collections.sort(someList, new Comparator<SomeObject>() {
public int compare(final SomeObject object1, final SomeObject object2) {
return object1.getSomeDate().after(object2.getSomeDate()) ? 1 : -1;
}}
);
The default ordering of Date will put newer dates after older dates so the oldest dates would be at the beginning of your list and the newest dates at the end. Comparators have always been hard to read in my opinion so I have switched to using google's Ordering objects that implement Comparator a little cleaner. For example your Comparator could be written like this:
Ordering<SomeObject> order = Ordering.natural().onResultOf(new Function<SomeObject, Date>() {
public Date apply(SomeObject object) {
return object.getDate();
}
});
Comparator<SomeObject> comparator = order; // Ordering implements Comparable so this would be legal to do
Collections.sort(someList, order);
The order Comparator that this code created would sort SomeObject objects based on their Date using the Date's natural ordering. But what makes Ordering really nice is some of extra methods change the order without having to write any more logic, for example to reverse the order of dates to be newest to oldest you just have to add a call to reverse():
Ordering<SomeObject> order = Ordering.natural().reverse().onResultOf(new Function<SomeObject, Date>() {
public Date apply(SomeObject object) {
return object.getDate();
}
});
This is old but may be someone can use it. It may be sorted using java8 as follows:
someList.sort(Comparator.comparing(listMember::dateProducingMethod))
By using lambdaj you could achieve the same result in an easier and more readable way as it follows:
sort(someList, on(SomeObject.class).getSomeDate());
Far better than writing an obscure inner class, isn't it?
Try this:
List<Date> list=new ArrayList<Date>();
//add some dates to list
Collections.sort(list, new Comparator<Date>() {
public int compare(final Date object1, final Date object2) {
return Long.compare(object1.getTime(),object2.getTime());
}}
);
Date.getTime() "converts" the date to a long, which is easier to compare and sort.
Anyway behind the curtain Longs are compared with this:
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
If you want to invert the sort, just multiply by -1 like this:
List<Date> list=new ArrayList<Date>();
//add some dates to list
Collections.sort(list, new Comparator<Date>() {
public int compare(final Date object1, final Date object2) {
return Long.compare(object1.getTime(),object2.getTime())*-1;
}}
);
Related
I've an arraylist of objects like arrlist =[obj1, obj2,obj3], where each object contains epochs and an Integer i.e. obj_i = {"1493275005401", 2} for all i . I want to sort arraylist on the basis of epochs. Being a beginner in java, I don't know much how to do this.
Note: I did some googling, came up with Collections.sort() but I'm not sure how to tell sort to sort on a specific field of the object.
Any help is appreciated.
Edit: Does it change the sorted output if I consider epoch(TIME) as just string instead of time.?
You can use Collections.sort with a Comparator, consider you have this :
List<Item> arrlist = Arrays.asList(new Item("1493275005401", 2), new Item("14932", 5),
new Item("778888", 1));
If you want to sort using the first Item which is String you can use :
Collections.sort(arrlist, (o1, o2) -> {
return o1.getName().compareTo(o2.getName());
});
If you want to sort using the second Item which is and int you can use :
Collections.sort(arrlist, (o1, o2) -> {
return o1.getId() - o2.getId();
});
Note : You can also sort your List with multiple itmes.
Edit
because epoch is an Integer you can convert it to BigInteger and compare your dates :
Collections.sort(arrlist, (o1, o2) -> {
return new BigInteger(o1.getName()).compareTo(new BigInteger(o2.getName()));
});
You can use Collections.sort(List<T>, Comparator<T>) to do this. You just need to specify a Comparator that uses the epoch component of your datatype.
Lets assume your type looks like this (the epoch seems to be a String):
class Container {
String epoch;
Integer i;
Container(String e, Integer ii){
epoch = e;
i = ii;
}
}
Then you can create a Comparator that compares the numerical (!) value of the epoch String:
class ContComparator implements Comparator<Container> {
#Override
public int compare(Container o1, Container o2) {
final Long epoch2 = Long.valueOf(o2.epoch);
final Long epoch1 = Long.valueOf(o1.epoch);
return epoch1.compareTo(epoch2);
}
}
And use it like this:
List<Container> arrlist = ... ;
Collections.sort(arrlist, new ContComparator());
Try Comparators:
list.sort(Comparator.comparing(obj -> Long.parseLong(obj.getEpoch())));
This is the newer syntax and Comparator API introduced with Java 8. The comparing method takes a function as a parameter that will extract the relevant attributes from the elements in the list.
If you read the JavaDoc of the comparing methods of Comparator you will find more information on how to modify the sorting further.
For a better understanding on what is happening:
list.sort(new Comparator<MyObject>() {
public int compare(MyObject o1, MyObject o2) {
return Long.parseLong(o1.getEpoch().toMillis()) - Long.parseLong(o2.getEpoch().toMillis());
}
})
For sorting by epoch time, we can do this
anyList.sort(Comparator.comparing(o.getEpoch()))
I have a object called project, I want to sort this project by 2 of its fields:
First: by Date(Gregorian Callander);
Second: by Name(String);
I want to sort the project by date form new to old. The only way I know to do this is to reverse the collection. However I want to sort the project with same date on name(alphabetically), where reverse also reverses this part of the sort.
Is there a way to reverse only part of the sort method, or any other way to get this sorted first by a date(reverse) and then a string(normal order a-z) ?
At the moment I am overriding the object compareTo method like so:
#Override
public int compareTo(Project project) {
int i = this.projectDate.compareTo(project.projectDate);
if(i != 0) return i;
return this.projectName.compareTo(project.projectName);
}
Date#compareTo returns a value < 0 if this Date is before the Date argument and a value > 0 otherwise.
If you want to reverse the sort from new to old, you can just return the negative compare result:
#Override
public int compareTo(Project project) {
int i = this.projectDate.compareTo(project.projectDate);
if(i != 0) return -i; // reverse sort
return this.projectName.compareTo(project.projectName);
}
In Java 8, the Comparator interface has a method thenComparing. You can use this method to create a comparator that compare by more than one field.
If you have a comparator to compare alphabetically and other to compare by dates, you can combine the comparator to sort by the field you want:
Comparator<Project> nameComparator = ...
Comparator<Project> dateComparator = ...
You can mix the comparator, using the reverse comparator if needed. These are some examples:
Comparator<Project> nameAndDateComparator = nameComparator.thenComparing(dateComparator);
Comparator<Project> nameAndReversedDateComparator = nameComparator.thenComparing(dateComparator.reversed());
Then, you can use the method sort as usual with the comparator that matches your needs.
If you are not using Java 8, you can create an utility class to combine your comparators:
public class CombinedComparator<T> implements Comparator<T> {
Comparator<T> firstComparator;
Comparator<T> secondComparator;
public CombinedComparator(Comparator<T> firstComparator, Comparator<T> secondComparator) {
this.firstComparator = firstComparator;
this.secondComparator = secondComparator;
}
#Override
public int compare(T o1, T o2) {
int result = firstComparator.compare(o1, o2);
return (result != 0) ? result : secondComparator.compare(o1, o2);
}
}
And you could create multiple fields comparators this way:
Comparator<Project> nameAndDateComparator = new CombinedComparator<Project>(nameComparator, dateComparator);
Comparator<Project> nameAndReversedDateComparator = new CombinedComparator<Project>(nameComparator, Collections.reverseOrder(dateComparator));
I have an Array of Hashmap and each hashmap contain 24 hour time as key-value pair.
I want to sort this array in ascending order of time. how can i achieve this?
here is snippet of my code:
HashMap[] arr = new HashMap[100];
for(int i=0;i<100;i++) {
HashMap<String,String> child=new HashMap<String,String>();
child.put("some_time","21:09"); //time changes per iteration(time is in 24-hour format)
arr[i]=child;
}
Here is the full code that will sort the array on time which is in hh:mm format:
HashMap<String,String>[] harr = new HashMap[10];
final DateFormat df = new SimpleDateFormat("kk:mm");
// prepare your data
for(int i=0;i<harr.length;i++) {
HashMap<String,String> child=new HashMap<String,String>();
int ss = (int)(Math.random() * (59 + 1));
//time changes per iteration(time is in 24-hour format)
child.put("some_time", String.format("21:%02d", ss));
harr[i]=child;
}
System.out.printf("map array is: %s%n", Arrays.deepToString(harr));
// now apply sort using a custom method
Arrays.sort(harr, new Comparator<HashMap<String,String>>() {
public int compare(HashMap<String,String> o1, HashMap<String,String> o2) {
String t1 = o1.get("some_time");
String t2 = o2.get("some_time");
try {
Date dt1 = df.parse(t1);
Date dt2 = df.parse(t2);
return dt1.compareTo(dt2);
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
});
System.out.printf("sorted map array is: %s%n", Arrays.deepToString(harr));
You can use Arrays.sort(T[], Comparator<T>). This allows you to pass an array of any type and write your own custom comparator method like this:
Arrays.sort(arr, new Comparator<HashMap>() {
public int compare(HashMap o1, HashMap o2) {
// Compare values you're interested in and return int as specified by Comparator API
}
});
See the API for details on what to return.
Before proceeding with this approach, do think about the comments and decide whether the array of hashmaps is the right way to go. If, as I pointed out, you have a bunch of maps, each containing large amounts of information, with one entry being your dates, then this may be the right thing to do, in which case the easiest way to sort the array would be to use Arrays.sort method:
HashMap[] arr=new Hashmap[100];
for(int i=0;i<100;i++){
HashMap<String,String> child=new HashMap<String,String>();
... // put all the info into the HashMap
child.put("some_time","21:09"); //time changes per iteration(time is in 24-hour format)
arr[i]=child;
}
Arrays.sort(arr, new Comparator<HashMap>() {
public int compare(HashMap o1, HashMap o2) {
String d1 = o1.get("some_time");
String d2 = o2.get("some_time");
//compare the two dates. If you're always in the same format, e.g. HH:MM (24 hours, two-digit hour, two-digit year), you might even be able to simply compare strings:
return d1.compareTo(d2);
}
});
The general approach is to write a Comparator to order a pair of your HashMap objects based on the key, and then pass that as a parameter to the Arrays.sort(T[], Comparator<T>) method.
Th comparator would look something like this:
Comparator<HashMap> DATE_ORDER = new Comparator<HashMap>() {
public int compare(Comparator<HashMap>h1, Comparator<HashMap>h2) {
String time1 = h1.get("some_time");
String time2 = h2.get("some_time");
return time1.compareTo(time2); // assuming that the time strings
// can be ordered that way
}
};
Having said that, your problem has the "smell" of trying to use Maps when they should really be writing custom classes.
As Bhavik points out, you may not be using the JDK to it's full potential - have a look at SortedMap which may be just what you're looking for; possibly with your own implementation of a Comparator.
SortedMap arr = new TreeMap<String,HashMap<String,String>>();
for ( int i=0 ; i<100 ; i++ )
{
Map<String,String> child = HashMap<String,String>();
child.put( "some_time" , "21:09" );
arr.put( "21:09" , child );
}
then you can use arr.values().iterator() to get your sorted children.
Cheers,
I have 2 array lists. One is an array list containing birthdays. The other is an array list of names.
I am sorting the array list of dates in descending order by date using
Collections.sort(birthdayList);
I want to have the array list of names be sorted in the same order that the birthday list was.
i.e.
unsorted
bdaylist namelist
1/20/1980 - Bob
3/15/1970 - Todd
8/25/1990 - Jeff
becomes
sorted
3/15/1970 - Todd
1/20/1980 - Bob
8/25/1990 - Jeff
What would be the most efficient way to do this in Java?
Thank you very much!
Create a Person class with 2 fields: name and birthday.
Put the persons in a list
sort with a custom comparator that compares the birthdays
Create a class like this:
public class Person implements Comparable<Person> {
private String name;
private Date date;
public Person(String name, Date date) {
this.name = name;
this.date = date;
}
public String getName() {
return name;
}
public Date getDate() {
return date;
}
#Override
public int compareTo(Person o) {
return this.date.compareTo(o.getDate());
}
}
Then you can sort the list of Person objects like this:
public static void main(String... args) {
LinkedList<Person> persons = new LinkedList<Person>();
persons.add(new Person("Name1", new Date())); //Specify different dates
persons.add(new Person("Name2", new Date()));
persons.add(new Person("Name3", new Date()));
Collections.sort(persons);
//Collections.sort(persons, Collections.reverseOrder()); //Reverse order
}
That's it.
Or another alternative is to use Comparator:
Collections.sort(persons, new Comparator<Person>() {
#Override
public int compare(Person o1, Person o2) {
return o1.getDate().compareTo(o2.getDate());
}
});
Reverse order:
Collections.sort(persons, Collections.reverseOrder(new Comparator<Person>() {
#Override
public int compare(Person o1, Person o2) {
return o1.getDate().compareTo(o2.getDate());
}
}));
Then you don't need to implement Comparable<Person> in your person class.
Don't sort two array lists; sort one array list filled with combined objects containing both the date and the name. That's really the only way.
The other answers about implementing Comparable and using it as the comparator are all indeed correct. But, if this also helps...
According to the Javadoc for Collections.sort, it is noted that sort() uses Modified Mergesort as the sorting algorithm. Correct me if I am wrong, but it is widely accepted that Merge Sort achieves the best possible running time for the worst-case scenario out of all sorting algorithms out there: O(n log n) (I'm not eliminating the fact that there may be other sort algorithms that also achieve O(n log n) in the worst case).
But, O(n log n) is only the best possible run time for an unbounded domain of values. If you have a bound on your domain, then you can get an even better runtime of O(n) using Bucket Sort.
I have an arraylist of objects with an age field internal to the objects. How can I sort them in ascending order dependant on their age?
Thanks for your time
Provide a comparator e.g.
Collections.sort(list, new Comparator<MyType>() {
public int compareTo(MyType t1, MyType t2) {
return t1.age - t2.age;
}
}
If the age can be a large range, this is not safe, but I assume the age will be between 0 and 2 billion. ;)
The Google Guava way to do this would be best I think:
Collections.sort(list, Ordering.natural().onResultOf(Person.ageFunction()));
This assumes the existence of Person.ageFunction():
public Function<Person, Integer> ageFunction() {
return new Function<Person, Integer>() {
#Override public Integer apply(Person person) {
return person.age;
}
};
}
Both Ordering and Google Guava are super handy, should be a tool in any Java programmer's toolbox. See the Guava home page.
Whenever you're comparing things that don't have a natural, consistent ordering, you shouldn't be implementing Comparable. Implement a Comparator instead. The reason for this is that the criteria for sorting is not intrinsic to the object...who can say that a 12 year old is "greater" than an 11 year old? What if the 11 year old is taller? Has an earlier birthday? Comparisons like these are arbitrary and are relevant to the context in which they are used, not intrinsically to the person itself.
This doesn't necessarily mean you have to expose any more data. You can easily expose the Comparator while still encapsulating the age field if you prefer. Something like this:
class Person {
int age;
public Comparator<Person> ageComparator() {
return new Comparator<Person>() {
public int compare(Person a, Person b) {
if ( a.age > b.age ) {
return 1;
} else if ( a.age < b.age ) {
return -1;
} else {
return 0;
}
}
};
}
}