Sorting a HashMap by date

12,633

Solution 1

Use a TreeMap instead of HashMap. it will be sorted automatically on insertion.

Map< Date, Object> m = new TreeMap< Date, Object>();

Alternatively, if you have an existing HashMap and want to create a TreeMap based on it, pass it to the constructor:

Map< Date, Object> sortedMap = new TreeMap< Date, Object>(m);

Hope it will help you.

Solution 2

Your best bet will be to use a SortedMap with the Comparator interface.

Here is an example:

public SortedMap<String, Object> getSortedMap(Map<String, Object> originalMap) {
    SortedMap<String, Object> tmpMap = new TreeMap<String, Object>(new Comparator<String>(){
        @Override
        public int compare(String key1, String key2) {
            //logic for comparing dates
        }           
    });
    tmpMap.putAll(originalMap);
    return tmpMap;
}

Solution 3

  1. Get all Entries by calling entrySet() method of Map

  2. Create a custom Comparator to sort entries based upon values

  3. Convert Entry set to List

  4. Sort Entry list by using Collections.sort() method by passing your value comparator

  5. Create a LinkedHashMap by adding entries in sorted order.

Look at example code @ Sort HasMap by value

Solution 4

For simplicity I am assuming that type of your map is something more like Map<String, MyClass> map where MyClass has method like getDate() which returns expPayDate.

My issue is what is the best way to determine the item with the newest date.

If you want to find single map entry which value contains max date you don't need to sort entire map which at best would give you O(n*logn). What you need is simple iteration of all elements in map and comparing them with current max, which will be O(n) operation.

You can use stream() (functionality added in Java 8) and its max method. This method needs Comparator and you can easily create one by using comparing method and passing lambda expression which will return value which should be used when comparing.

So your code can look like

//import java.util.Map.Entry;

Optional<Entry<String, MyClass>> max = map.entrySet().stream()
        .max(Comparator.comparing(e -> e.getValue().getDate()));

Entry<String, MyClass> entry = max.get();
MyClass maxMC = entry.getValue();

If you can't use Java 8 you can write your own method which will iterate over elements and find max. Such method can look like

public static <T> T max(Iterable<T> iterable, Comparator<T> comp) {
    Iterator<T> it = iterable.iterator();
    T max = null;
    if (it.hasNext()) {
        max = it.next();
    }
    while (it.hasNext()) {
        T tmp = it.next();
        if (comp.compare(max, tmp) < 0)
            max = tmp;
    }
    return max;
}

and you can use it like

Comparator<Entry<String, MyClass>> myComparator = new Comparator<Entry<String, MyClass>>() {
    @Override
    public int compare(Entry<String, MyClass> o1, Entry<String, MyClass> o2) {
        return o1.getValue().getDate().compareTo(o2.getValue().getDate());
    }
};
Entry<String, MyClass> maxEntry = max(map.entrySet(), myComparator);
MyClass max = maxEntry.getValue();

Solution 5

If you just need the minimum or maximum date, a simple for each loop might be sufficient:

Date maxDate = null;
for (Entry<String, Object> item: hashMap.entrySet()) 
    if (maxDate == null || maxDate before((Date)item.getValue())) 
        maxDate = (Date)item.getValue();

This way complexity is only O(n) and insert and delete operations are cheaper than using a sortedMap. Anyway, I think patstuart's suggestion (using a sortedMap) is more elegant.

Share:
12,633
Bill F
Author by

Bill F

I have been a N/D developer since about 1995 and have created many N/D applications for many different companies (world wide), they have generally been Notes Client focused with some being web enabled secondarily. So I have considerable experience in @Formula and LS. Have Now been working with XPages for the past year and challenging, but very rewarding. Can now do a number of things in XPages that I wished that I could have done in Notes for years.

Updated on July 27, 2022

Comments

  • Bill F
    Bill F almost 2 years

    In a Java class I have a method to reOrder an existing HashMap by date. The HashMap is of a type <String, Object> where the Object contains a field called expPayDate and the key string is a sequential number turned into a string.. So I need to loop through the items in the sourceMap and find the item with the newest date then copy it to a tempMap in the correct order. My issue is what is the best way to determine the item with the newest date.

  • Eric McCormick
    Eric McCormick over 8 years
    The OP's question was in regards to a JEE implementation that is specifically 1.6 (for now). The XPages runtime can not benefit (yet) from any Java 8 implementations. I retraced my down vote as this is not something obvious to a non-XPages dev and is unique to the platform, but I believe this provides some reasonable merit regarding all Java implementations and highlights the need for the runtime to be updated to a higher Java version. So good input, but @Bill won't be able to use it.
  • Pshemo
    Pshemo over 8 years
    @EricMcCormick If problem is only with Java 8, then it means that there is no real problem since this solution can be easily rewritten to older versions of Java. Main part of my answer was to show that we don't actually need to create separated sorted map (which will be O(n*logn) bit in case of finding max we van simply iterate over all elements once which is O(n)). I will rewrite my code for older versions of Java.
  • Eric McCormick
    Eric McCormick over 8 years
    No worries, I agree. It's a perfectly legitimate answer... to most situations; one of my frustrations with the platform (for now, we've been promised a newer JVM is coming).
  • fps
    fps over 8 years
    The date is an atribute of the value, not the key.
  • Pshemo
    Pshemo over 8 years
    It is worth noticing that Comparator used in TreeMap us used to compare keys, not values, nor dates. We need to each time use key to get value, read its date attribute. Then we can use same for second key and compare dates.
  • patstuart
    patstuart over 8 years
    @Pshemo good catch. I changed the generics type of my answer to use String instead of Object.
  • Pshemo
    Pshemo over 8 years
    You could also change name of compare method parameters to key1 and key2.
  • user207421
    user207421 over 8 years
    Don't use quote formatting for text that isn't quoted.
  • Bill F
    Bill F over 8 years
    I use the HashMap because I load it based on the sort order of a ViewEntryCollection, but for ease of access I use it in the HashMap with a sequential number. I do this because I use the HashMap as the datasource for a repeat control.so I can use the index from the repeat to get the correct HashMap. So when I start the Hashmap is in the right order, but if I add a new 'Line Item' to the HashMap it appears at the end of the list. I don't want to reload the HashMap from disk.
  • Bill F
    Bill F over 8 years
    So my solution is to read each "PaymentItem" from the HashMap and store it in a tempMap which is a TreeMap<expPayDate,PaymentItem>. Now my items are in the right order, then copy them back into the original HashMap with the sequential key. Because it is all done in memory it appears to be pretty fast and does not repeated reads back to the server. Some of the other suggestions above might be more efficient but this seems to work well. Thanks for all the feed back, appreciate that.