Sort Array of Hashmap by ascending time - java

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,

Related

How to create a HashMap that would have String as key and the value would be another HashMap from one list of custom object?

I have a list of custom object,
public class Assignmentsdata {
String assignmentId;
String teacherId;
String groupName;
String sectionId;
String levelId;
String startTime;
}
ArrayList<Assignmentsdata> list = new ArrayList<>();
lets say there are 20 elements in that list.
Now I want to get the output which is a hashmap of startTime as a key and the Value would be a new HashMap of GroupID and a list of Assignments of those that had the same groupName.
OutPut Example
HashMap<startTime,HasMap<groupName,List> hashMap = new HashMap();
a little more insight about the problem: First I want to categorise based on startTime(Month) then i want to categorise based on groupName, Thanks in advance.
I have successfully categorised based on group name and created a map through below code:
for( int i = 0; i<assignmentsdataArrayList.size();i++ ){
if (hashMap.size()>0){
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}else {
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}
After that I am lost on how to categorise this hashmap based on the startDate and create a hashmap that would look like the above hashmap in the output heading.
your code may throw a NullPointerException at the first if branch
if (hashMap.size()>0)
{hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
the map.size()>0 doesnt means the Value of GroupName has put a new ArrayList already.
the anwser of using loop should like this
Map<String, Map<String, List<Assignmentsdata>>> map = new HashMap<>();
for (Assignmentsdata assignmentsdata : list) {
if (!map.containsKey(assignmentsdata.getStartTime())) {
map.put(assignmentsdata.getStartTime(), new HashMap<>());
}
Map<String, List<Assignmentsdata>> startTimeMap = map.get(assignmentsdata.startTime);
if (!startTimeMap.containsKey(assignmentsdata.getGroupName())) {
startTimeMap.put(assignmentsdata.getGroupName(), new ArrayList<>());
}
startTimeMap.get(assignmentsdata.groupName).add(assignmentsdata);
}
or you could use the java stream().collect(Collectors.groupingBy()) api to get the result easily
Map<String, Map<String, List<Assignmentsdata>>> result = list.stream()
.collect(Collectors.groupingBy(Assignmentsdata::getStartTime,Collectors.groupingBy(Assignmentsdata::getGroupName)));
I am answering my own question as I solved it if anyone has a better answer please passed your answer aswell, ill accept another answer suitable and efficient answer.
for( int i = 0; i<assignmentsdataArrayList.size();i++ ){
if (hashMap.size()>0){
if (hashMap.get(assignmentsdataArrayList.get(i).getGroupName())==null){
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}else{
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}else {
hashMap.put(assignmentsdataArrayList.get(i).getGroupName(),new ArrayList<Assignmentsdata>());
hashMap.get(assignmentsdataArrayList.get(i).getGroupName()).add(assignmentsdataArrayList.get(i));
}
}
// above part is already in the question. the second part i looped through the hashMap then the list once again, and checking if list and map entry have same group name, then made the startdate key that indexed element from the list.
HashMap<String, Map.Entry<String, ArrayList<Assignmentsdata>>> hashMapHashMap = new HashMap<>();
for (var entry : hashMap.entrySet()){
for( int j = 0; j<assignmentsdataArrayList.size();j++ ){
if (assignmentsdataArrayList.get(j).getGroupName()==entry.getKey()){
hashMapHashMap.put(assignmentsdataArrayList.get(j).getStartTime(),entry);
}
}
hashMapHashMap.put(entry.getValue().get())
}

Sort arraylist of objects containing epochs in Java

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()))

Trim Java ArrayList to distinct row with the newest date

I have a List of MyData as below.
It consist of multiple rows of MyData objects.
There are some with same key but different date and name
public class MyData {
String name;
String key;
String date;
// ... constructor and other codes omitted here
}
List<MyData> myDataList;
I'm thinking of trimming the list to distinct key based on the newest date
e.g. If I have
*Name* *key* *date*
ABC 12 2016-10-09
FGH 10 2016-10-18
IJK 10 2016-10-08
DEF 12 2016-10-19
then the trim result should be
*Name* *key* *date*
DEF 12 2016-10-19
FGH 10 2016-10-18
What's the best way to do this algorithmically?
Note: I'm on Java 7, can't use the Stream feature of Java 8. (This is for Android Development, Java 8 is not supported yet).
Assuming you use real date types for date attribute you could do this:
private Collection<MyData> trim(List<MyData> data) {
Map<String, MyData> result = new HashMap<>();
for (MyData item : data) {
MyData lastItem = result.get(item.getKey());
if (lastItem == null || lastItem.getDate().before(item.getDate())) {
result.put(item.getKey(), item);
}
}
return result.values();
}
You could probably reach same results using streams.
You can use a HashMap and update object corresponding to key only if it is more recent. I let you write the function to compare two dates.
HashMap<Integer, MyData> trimedData = new HashMap<>();
for (MyData d : myDataList){
MyData dataSaved= trimedData.get(d.key);
if (dataSaved!= null){
if(d.date > dataSaved.data){ // Here use correct method to compare date
trimedData.put(d.key, d);
}
}
else trimedData.put(d.key, key);
}
You can use streams, look at this example:
ArrayList<String> strings = new ArrayList<>();
strings.add("cbab");
strings.add("abab");
strings.add("dabab");
strings.add("ddabab");
Map<Integer, Optional<String>> collect = strings
.stream()
.collect(Collectors.groupingBy(String::length,
Collectors.maxBy(Comparator.comparingInt((c) -> (int) charAt(0)))));
System.out.println(collect);
Change String::length to MyData::key and comparator to comparing dates (Collectors.maxBy((MyData d1, Mydate d2) -> d1.getDate().compareTo(d2.getDate()).

Sort ArrayList with times in Java

I have a List<String> that contains a list of times from 8:00 am to 4:00 pm.
When I show it in output it appears unsorted, and when I use Collections.sort(myList); it sorts it as from 1:00 pm to 8:00 am.
How could I sort my list from 8:00am to 4:00pm ?
Don't reinvent the wheel, use collection (or Lambdas if java8 is allowed)
How??:
keep the list as strings, but use an Anonymous comparator, in there, parse the string to dates, compare them and there you have it.
here a snippet:
List<String> l = new ArrayList<String>();
l.add("8:00 am");
l.add("8:32 am");
l.add("8:10 am");
l.add("1:00 pm");
l.add("3:00 pm");
l.add("2:00 pm");
Collections.sort(l, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
try {
return new SimpleDateFormat("hh:mm a").parse(o1).compareTo(new SimpleDateFormat("hh:mm a").parse(o2));
} catch (ParseException e) {
return 0;
}
}
});
System.out.println(l);
Convert your Strings to Dates and sort the dates. In Java in general you should always handle the objects as they are, not Strings. Strings are names or other texts, when there is a special meaning of a String you better convert into that meaningful object.
Here is a short program for what you want to do.
public static void main(String[] args) throws ParseException {
ArrayList<String> times = new ArrayList<String>();
times.add("8:00 pm");
times.add("8:00 am");
times.add("7:00 pm");
times.add("7:00 am");
ArrayList<Date> dates = new ArrayList<Date>();
DateFormat format = new SimpleDateFormat("h:m a", Locale.ENGLISH);
for(String time : times){
dates.add(format.parse(time));
}
Collections.sort(dates);
System.out.println(dates);
}
Steps:
Convert each string to a standardized Date
Sort using Collections.sort()
DetailsVOTemp model has time and add set-get method and I already have a list which is list with name of list.
Get the time and latlong from the list and store in two arraylist than finally sort it
List< DetailsVOTemp> firstlist = new ArrayList<>();
List<DetailsVOTemp> secondlisr = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
DetailsVOTemp mDetailsVOTemp = new DetailsVOTemp();
mDetailsVOTemp.setTime(list.get(i).getTime());
mDetailsVOTemp.setAdd(list.get(i).getLatLong());
mVoTemps.add(mDetailsVOTemp);
}
for (int i = 0; i < list.size(); i++) {
DetailsVOTemp mDetailsVOTemp = new DetailsVOTemp();
mDetailsVOTemp.setTime(list.get(i).getDropOffTime());
mDetailsVOTemp.setAdd(list.get(i).getDropLatLong());
mVoTemps1.add(mDetailsVOTemp);
}
mVoTemps.addAll(mVoTemps1);
Collections.sort(mVoTemps, new Comparator<DetailsVOTemp>() {
#Override
public int compare(DetailsVOTemp o1, DetailsVOTemp o2) {
return o1.getTime().compareTo(o2.getTime());
}
});
StringBuilder mBuilder = new StringBuilder();
StringBuilder mBuilder1 = new StringBuilder();
for (int i = 0; i < mVoTemps.size(); i++) {
mBuilder1.append(mVoTemps.get(i).getTime() +" :: ");
mBuilder.append(mVoTemps.get(i).getAdd() +" :: ");
}
Log.d("Time : ", mBuilder1.toString());
Log.d("Address : ", mBuilder.toString());
Use 24 hour time format in your list and then sort it.
You can revert it back to AM and PM anytime.
Like others I recommend not reinventing the wheel, and I also recommend discarding the old and outdated classes SimpleDateFormat and Date. We have so much better these days.
Given
static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("h:mm a", Locale.ENGLISH);
we can do
Collections.sort(listOfTimeStrings,
Comparator.comparing(
(String s) -> LocalTime.parse(s.toUpperCase(), dtf)));
This will work nicely for a few hundred strings, maybe more. It will, however, parse each string each time two strings are to be compared. That could be many times. If you want to parse each string only once, instead do:
List<String> sortedList = listOfTimeStrings.stream()
.map(String::toUpperCase)
.map(s -> LocalTime.parse(s, dtf))
.sorted()
.map(dtf::format)
.map(String::toLowerCase)
.collect(Collectors.toList());
I have taken it literally when you give am and pm in lowercase, so I am converting to uppercase before the parsing and back to lowercase after formatting. Depending on your data you may skip these steps.

Date Sorting - Latest to Oldest

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;
}}
);

Categories

Resources