Reverse order of LinkedHashMap to LinkedHashMap or ArrayList - java

I have a LinkedHashMap<String,String> which looks something like this (don't really know how to illustrate a HashMap):
{
"10/10/2010 10:10:10" => "SomeText1",
"10/10/2019 10:10:19" => "SomeText2",
"10/10/2020 10:10:20" => "SomeText3",
"10/10/2021 10:10:21" => "SomeText4"
}
And I want to put it like this:
{
"10/10/2021 10:10:21" => "SomeText4",
"10/10/2020 10:10:20" => "SomeText3",
"10/10/2019 10:10:19" => "SomeText2",
"10/10/2010 10:10:10" => "SomeText1"
}
I have written this solution which works because the result I want is an ArrayList, but i was thinking if there was an easier way to reverse the LinkedHashMap maintaining the same type using a tool like sort for example.
private LinkedHashMap<String, String> map = new LinkedHashMap<>();
int sizeOfHashMap = map.size();
ArrayList reversedHashToArrayList = new ArrayList(map.size());
for (Map.Entry<String,String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
reversedHashToArrayList.add(0,entry);
}

A LinkedHashMap orders by insertion; it would be more logical to sort on the associated date time:
private SortedMap<LocalDateTime, String> map = new TreeMap<>(Comparator.naturalOrder()
.reversed());
LocalDateTimeFormatter formatter = LocalDateTimeFormatter.ofPattern("MM/dd/uuuu HH:mm:ss");
map.put(LocalDateTime.parse("10/10/2010 10:10:10", formatter), "...");
To specify that the map is sorted, there is the interface SortedMap. Better use an interface, which is more versatile. The implementation class for a sorted map is the TreeMap. However you want a reversed comparison.
You could use a Local specific pattern. Mind that above I chose Month/Day and not the British Day/Month.

If your motive is just to reverse the map ( show in descending order ) you can use
Java.util.TreeMap.descendingMap() : It returns a reverse order view of the mappings contained in the map`
LinkedHashMap<String,String> map = .... //this is your intial hashmap
TreeMap<String,String> tmap = new TreeMap<>(map);
map.clear();
map.putAll(tmap.descendingMap());
This will do the trick.

Here Is My Own Written Logic for you. without using any built in functions to reverse:
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("10/10/2010 10:10:10", "SomeText1");
map.put("10/10/2019 10:10:19", "SomeText2");
map.put("10/10/2020 10:10:20", "SomeText3");
map.put("10/10/2021 10:10:21", "SomeText4");
LinkedHashMap<String, String> reversed = new LinkedHashMap<>();
String[] keys = map.keySet().toArray(new String[map.size()]);
for (int i = keys.length - 1; i >= 0; i--) {
reversed.put(keys[i], map.get(keys[i]));
}

If you want to keep using a LinkedHashMap reversing it while keeping it somewhat efficient is not as easy. This is a solution that reverses a given LinkedHashMap using the iterator order (which is predictable for a LinkedHashMap and therefore probably what you are looking for).
Note that other solutions like using a SortedMap or a TreeMap are probably still better. Yet, for the sake of sticking to your original question, here is a solution:
public static <K, V> LinkedHashMap<K, V> reverse(LinkedHashMap<K, V> map)
{
LinkedHashMap<K, V> reversedMap = new LinkedHashMap<K, V>();
ListIterator<Entry<K, V>> it = new ArrayList<>(map.entrySet()).listIterator(map.entrySet().size());
while (it.hasPrevious())
{
Entry<K, V> el = it.previous();
reversedMap.put(el.getKey(), el.getValue());
}
return reversedMap;
}
Note that you won't get around wrapping the entry set into an ArrayList sadly as only that provides you with an ListIterator which can be initialized to any point other than the first element. Having something like a reverseIterator() method would simplify life a lot - sadly there is none available.
Complexity wise you iterate the list twice with this approach, first for the listIterator call from start to the last element and then once more from the back to the front when using previous. So you are looking at O(2n) here.

Related

How do I reverse the values of a Map when one type is a Set of Integers

For example how do I reverse the key and value datatypes from something like this:
TreeMap<Set<Integer>, Integer>
...into this:
TreeMap<Integer, Set<Integer>>
If you're using Java8, you can do:
TreeMap<Set<Integer>, Integer> map = ....;
Map<Integer, Set<Integer>> result =
map.entrySet()
.stream()
.map(entry -> new AbstractMap.SimpleEntry(entry.getValue(), entry.getKey())
.collect(Collectors.toMap());
Iterate over the entry set and put them reversely in a new TreeMap. The following generic method will reverse every map.
public static <K, V> TreeMap<V, K> reverse(TreeMap<K, V> map) {
TreeMap<V, K> result = new TreeMap<V, K>();
for (Entry<K, V> e : map.entrySet())
result.put(e.getValue(), e.getKey());
return result;
}
Important
If a value is present two times, you will lose the key with the smallest value.
Example:
public static void main(String[] args) {
TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
map.put(1, 2);
map.put(2, 2);
System.out.println(reverse(map));
}
Output:
{2=2}
The tuple {1,2} is lost since the value 2 was presents multiple times!
Maps are not easilly reversible, And rightly so.
Reversing maps might not work.
In a Map Keys are obviously unique but values have no such constraint.
I don't know what the problem you're facing is, but it sounds as if there is a better design to solve it.
Perhaps you should use a BiMap?
It's essentialy a two way map in which both the "keys" and the "values" are unique. It allows efficient lookup both from the keys and from the values.
Java doesn't have a built in BiMap but google Guava and Apache Commons do.

Get key of minimum value in a Hashtable

I have a Hashtable in java like below and I'm trying to get the key that has the minimum value. Obviously I can iterate through all the elements to find it but is there an easier way to do it?
Hashtable<Object, Integer> hash= new Hashtable<Object, Integer>();
Using a Hashtable, no. But you could instead use a TreeMap.
A Red-Black tree based NavigableMap implementation. The map is sorted
according to the natural ordering of its keys, or by a Comparator
provided at map creation time, depending on which constructor is used.
It has a method firstKey() which provides the exact functionality you want.
Grr, values, not keys. No, then you will need to iterate.
I'd say in that case you should use a separate Map (Multimap?) to store the reverse association.
Map<Object, Integer> hash= new Hashtable<Object, Integer>();
SortedSetMultimap<Integer, Object> reverse = TreeMultimap.create();
whenever you put key, value something into hash, also put value, key into reverse.
then retrieve the lowest value using reverse.keySet().first()
(this solution requires Guava)
Instead of iterating yourself you can use library function Collections.min(Collection,Comparator) over entrySet().
SAMPLE
public static void main(String[] args) {
HashMap<String,Integer> map = new HashMap<String,Integer>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
System.out.println(
Collections.min(map.entrySet(), new Comparator<Map.Entry<String,Integer>>() {
#Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
return o1.getValue().intValue() - o2.getValue().intValue();
}})
.getKey()
);
}
It looks like the easiest way to do it is in fact iterating over the elements. If the Hashtable name is hash:
Object minObj= null;
int min= Integer.MAX_VALUE;
for(Map.Entry<Object, Integer> x: hash.entrySet()){
if(x.getValue() < min){
min= x.getValue();
minObj= x.getKey();
}
}
Minimum value can be findout in this way as well,
Hashtable h = new Hashtable();
h.put(10, "aaa");
h.put(1, "aab");
h.put(12, "aabwqkjdg");
Set set = h.keySet();
TreeSet treeSet= new TreeSet();
treeSet.addAll(set);
System.out.println("Last :"+treeSet.first());
I just took example of keys as integer.

How do I sort this hashmap?

for(int i=0;i<videos.length();i++){
HashMap<String, String> map = new HashMap<String, String>();
JSONObject e = videos.getJSONObject(i);
map.put("id", String.valueOf(i));
map.put("title", e.getString("title"));
map.put("description", e.getString("description"));
mylist.add(map);
}
Hi, I am trying to sort the code above alphabetically. I know tree maps, are supposed to be used for this sorta thing, but it would be a bigger hassle to to do that. I am having errors arranging the hash map, and have looked at numerous examples.
It is not a big hassle to use a TreeMap.
for(int i=0;i<videos.length();i++){
Map<String, String> map = new TreeMap<String, String>();
JSONObject e = videos.getJSONObject(i);
map.put("id", String.valueOf(i));
map.put("title", e.getString("title"));
map.put("description", e.getString("description"));
mylist.add(map);
}
Even if that's a lot of hassle (e.g. if you made the mistake of declaring mylist to be a List<HashMap>), you've got little choice. A HashMap is inherently unsorted / unordered and you can't change that fact. If you could use a LinkedHashMap instead, you could add the entries in alphabetical order, but if you can change the map type you may as well use a TreeMap.
You cannot sort a HashMap.
"The Map interface provides three collection views, which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings. The order of a map is defined as the order in which the iterators on the map's collection views return their elements. Some map implementations, like the TreeMap class, make specific guarantees as to their order; others, like the HashMap class, do not."
Cited form: http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
If you're trying to sort the list, you need to implement a comparator. You can do something like this:
public class VideoComparator implements Comparator<Map<String, String>> {
private final String key;
public VideoComparator(String key) {
this.key = key;
}
public boolean equals(Object object) {
return this == object;
}
public int compare(Map<String, String> map1, Map<String, String> map2) {
return map1.get(key).compareTo(map2.get(key));
}
}
Then you can sort your maps by title like this:
Collections.sort(mylist, new VideoComparator("title"));

Iterating through a LinkedHashMap in reverse order

I have a LinkedHashMap:
LinkedHashMap<String, RecordItemElement>
that I need to iterate through from a given key's position, backwards. So if I was given the 10th item's key, I'd need iterate backwards through the hashmap 9, 8, 7 etc.
The question requires a LinkedHashMap in reverse order, some answers suggesting using a TreeSet but this will reorder the map based upon the key.
This solution allows the iteration over the original LinkedHashMap not the new ArrayList as has also been proposed:
List<String> reverseOrderedKeys = new ArrayList<String>(linkedHashMap.keySet());
Collections.reverse(reverseOrderedKeys);
for (String key : reverseOrderedKeys) {
RecordItemElement line = linkedHashMap.get(key);
}
The HashMap:
HashMap<Integer, String> map = new HashMap<Integer, String>();
Reverse iterating over values:
ListIterator<Sprite> iterator = new ArrayList<String>(map.values()).listIterator(map.size());
while (iterator.hasPrevious()) String value = iterator.previous();
Reverse iterating over keys:
ListIterator<Integer> iterator = new ArrayList(map.keySet()).listIterator(map.size());
while (iterator.hasPrevious()) Integer key = iterator.previous();
Reverse iterating over both:
ListIterator<Map.Entry<Integer, String>> iterator = new ArrayList<Map.Entry<Integer, String>>(map.entrySet()).listIterator(map.size());
while (iterator.hasPrevious()) Map.Entry<Integer, String> entry = iterator.previous();
You don't have to iterate through it. But it would be handy to pull the keys off and store it in a list. Thats the only way you can do indexOf() type operations.
List<String> keyList = new ArrayList<String>(map.keySet());
// Given 10th element's key
String key = "aKey";
int idx = keyList.indexOf(key);
for ( int i = idx ; i >= 0 ; i-- )
System.out.println(map.get(keyList.get(i)));
new LinkedList(linkedHashMap.keySet()).descendingIterator();
Using "user22745008" solution and labdas with some generics you can have a very neat solution as a method:
public static <T, Q> LinkedHashMap<T, Q> reverseMap(LinkedHashMap<T, Q> toReverse)
{
LinkedHashMap<T, Q> reversedMap = new LinkedHashMap<>();
List<T> reverseOrderedKeys = new ArrayList<>(toReverse.keySet());
Collections.reverse(reverseOrderedKeys);
reverseOrderedKeys.forEach((key)->reversedMap.put(key,toReverse.get(key)));
return reversedMap;
}
This is an old question, but I think it's lacking an answer that takes a newer approach. The following uses Java 9 features:
Deque<Map.Entry<String, RecordItemElement>> top = map.entrySet().stream()
.takeWhile(e -> !givenKey.equals(e.getKey()))
.collect(Collectors.toCollection(ArrayDeque::new));
The code above streams the map's entryset, keeping entries until a key equal to the given key is found. Then, the entries are collected to an ArrayDeque.
One detail is missing, though. Depending on whether you need the entry that matches the given key to also be included in the result or not, you might need to manually add it to the deque. If you don't want it added, then you're done. Otherwise, simply do:
top.add(Map.entry(givenKey, map.get(givenKey)));
Now, to iterate the Deque in reverse order, simply use its descendingIterator():
Iterator<Map.Entry<String, RecordItemElement>> descIt = top.descendingIterator();
It's worth mentioning that this approach only works if the stream is sequential. Anyways, we wouldn't have gained anything using a parallel stream here.

How print out the contents of a HashMap<String, String> in ascending order based on its values?

I have this HashMap that I need to print out in ascending order according to the values contained in it (not the keys).
But the order when I print it out is seemingly random.
What's the best way to print it out in ascending value order?
Map<String, String> codes = new HashMap<String, String>();
codes.put("A1", "Aania");
codes.put("X1", "Abatha");
codes.put("C1", "Acathan");
codes.put("S1", "Adreenas");
In other words, the example above should print out as this:
A1, Aania
X1, Abatha
C1, Acathan
S1, Adreenas
You aren't going to be able to do this from the HashMap class alone.
I would take the Map<String, String> codes, construct a reverse map of TreeMap<String, String> reversedMap where you map the values of the codes Map to the keys (this would require your original Map to have a one-to-one mapping from key-to-value). Since the TreeMap provides Iterators which returns entries in ascending key order, this will give you the value/key combination of the first map in the order (sorted by values) you desire.
Map<String, String> reversedMap = new TreeMap<String, String>(codes);
//then you just access the reversedMap however you like...
for (Map.Entry entry : reversedMap.entrySet()) {
System.out.println(entry.getKey() + ", " + entry.getValue());
}
There are several collections libraries (commons-collections, Google Collections, etc) which have similar bidirectional Map implementations.
You'll need to make a list of the keys, sort them according to the corresponding values, then iterate over the sorted keys.
Map<String, String> map = getMyMap();
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys, someComparator);
for (String key: keys) {
System.out.println(key + ": " + map.get(key));
}
As for what to use for someComparator, here are some handy, generic Comparator-creating routines I often find useful. The first one sorts by the values according to their natural ordering, and the second allows you to specify any arbitrary Comparator to sort the values:
public static <K, V extends Comparable<? super V>>
Comparator<K> mapValueComparator(final Map<K, V> map) {
return new Comparator<K>() {
public int compare(K key1, K key2) {
return map.get(key1).compareTo(map.get(key2));
}
};
}
public static <K, V>
Comparator<K> mapValueComparator(final Map<K, V> map,
final Comparator<V> comparator) {
return new Comparator<K>() {
public int compare(K key1, K key2) {
return comparator.compare(map.get(key1), map.get(key2));
}
};
}
It's time to add some lambdas:
codes.entrySet()
.stream()
.sorted(Comparator.comparing(Map.Entry::getValue))
.forEach(System.out::println);
the for loop of for(Map.Entry entry: codes.entrySet()) didn't work for me. Used Iterator instead.
Iterator<Map.Entry<String, String>> i = codes.entrySet().iterator();
while(i.hasNext()){
String key = i.next().getKey();
System.out.println(key+", "+codes.get(key));
}
you just need to use:
Map<>.toString().replace("]","\n");
and replaces the ending square bracket of each key=value set with a new line.
Java 8
map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEach(System.out::println);
Create a TreeMap<String,String>
Add each of the HashMap entries with the value as the key.
iterate the TreeMap
If the values are nonunique, you would need a list in the second position.
You can use a list of the entry set rather than the key set and it is a more natural choice given you are sorting based on the value. This avoids a lot of unneeded lookups in the sorting and printing of the entries.
Map<String, String> map = ...
List<Map.Entry<String, String>> listOfEntries = new ArrayList<Map.Entry<String, String>>(map.entrySet());
Collections.sort(listOfEntries, new SortByValueComparator());
for(Map.Entry<String, String> entry: listOfEntries)
System.out.println(entry);
static class SortByValueComparator implements Comparator<Map.Entry<String, String>> {
public int compareTo(Map.Entry<String, String> e1, Map.Entry<String, String> e2) {
return e1.getValue().compateTo(e2.getValue());
}
}
the simplest and shortest code i think is this:
public void listPrinter(LinkedHashMap<String, String> caseList) {
for(Entry entry:caseList.entrySet()) {
System.out.println("K: \t"+entry.getKey()+", V: \t"+entry.getValue());
}
}
The simplest solution would be to use a sorted map like TreeMap instead of HashMap.
If you do not have control over the map construction, then the minimal solution would be to construct a sorted set of keys. You don't really need a new map.
Set<String> sortedKeys = new TreeSet<String>();
sortedKeys.addAll(codes.keySet());
for(String key: sortedKeys){
println(key + ":" + codes.get(key));
}
Try:
try
{
int cnt= m.getSmartPhoneCount("HTC",true);
System.out.println("total count of HTC="+cnt);
}
catch (NoSuchBrandSmartPhoneAvailableException e)
{
// TODO Auto-generated catch
e.printStackTrace();
}
SmartPhone[] sp=new SmartPhone[4];
sp[0]=new SmartPhone(1,"HTC","desire","black",20000,10,true,true);
sp[1]=new SmartPhone(2,"samsung","grand","black",5000,10,false,true);
sp[2]=new SmartPhone(14,"google nexus","desire","black",2000,30,true,false);
sp[3]=new SmartPhone(13,"HTC","desire","white",50000,40,false,false);
while (itr.hasNext()) {
Vehicle vc=(Vehicle) itr.next();
if(vc.getVehicleType().equalsIgnoreCase(s)) {
count++;
}
}

Categories