How do I sort this hashmap? - java

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

Related

How to sort a hashmap consisting of Class objects as key and another hashmap as value in java?

I'm fairly new to Java and found some resources on how to sort the hashmap based on certain attributes of the key object. However, I'm still not able to figure out what I'm missing in my code.
I would really appreciate any help.
I have a Monkey class, one of whose attribute is name. And, the location of the monkey could be either {"isolationId" : someInteger} or {"enclosureId": someInteger}.
And my hashmap looks like this:
HashMap<Monkey, HashMap<String, Integer>> monkeyAndLocation = new HashMap<Monkey, HashMap<String, Integer>>();
Now, I want to sort the monkeyAndLocation with respect to the name attribute of the monkey object.
Can you help me with this?
If you want a sorted copy of your Map, you could just do (apparently your map should be filled with something):
private Map<Monkey, HashMap<String, Integer>> sortMonkeys(){
Map<Monkey, HashMap<String, Integer>> monkeyAndLocation = new HashMap<Monkey, HashMap<String, Integer>>();
return new TreeMap<>(monkeyAndLocation);
}
// the Monkey class should reside in a file of its own!
private static class Monkey implements Comparable<Monkey>{
#Override
public int compareTo(Monkey other){
return name.compareTo(other.name);
}
String name;
Integer isolationId;
Integer enclosureId;
}
The TreeMap sorts by the natural order of its keys. So by implementing Comparable you set the natural order to the order of the names of the monkeys.
First things first: You cannot sort a HashMap. Technically you can't sort any Map type, but some map types can control the iteration order of their entries to emulate being sorted.
A TreeMap maintains order of its entries, so load one with the contents of your map, providing the Comparator it should use to order its entries.
First change the definition of your map to its abstract type - see Liskov substitution principle:
Map<Monkey, Map<String, Integer>> monkeyAndLocation = new HashMap<>();
To convert this map to one that is "sorted" (iterates in sort order):
Map<Monkey, Map<String, Integer>> monkeyAndLocationSorted
= new TreeMap<>(Comparators.comparing(Monkey::getName));
monkeyAndLocationSorted.putAll(monkeyAndLocation);

Sort every Map in List by Set of keys

I have List of LinkedHashMap like List<Map<String, String>>. Every Map has the same number of elements and every Map has the same keys.
The second element is LinkedHashSet<String> - set of keys.
Now I would like to order every Map from List by keys. Sort ordering is in LinkedHashSet<String>.
My attempt is iterate by List<Map<String, String>>. For every Map create new Map and iterate by Set. To the new Map put key and value from old Mapwhere key is taken from Set. In code:
private List<Map<String, String>> sort(List<Map<String,String> result, LinkedHashSet<String> keys){
List<Map<String, String>> sortedResult = new LinkedList<>();
result.forEach(map -> {
Map<String, String> sortedMap = new LinkedHashMap<>();
keys.forEach(key -> {
sortedMap.put(key, map.get(key));
});
sortedResult.add(sortedMap);
});
return sortedResult;
}
I think it is a little bit complicated and in my opinion there exsists better way to do that.
You have a LinkedHashMap which tries to maintain only the order of insertion of keys, not the natural-ordering of keys. One thing you can do is to maintain a list of keys outside the map and sort them and re-insert the <key,value> pairs as per the order of the sorted list of keys. So it seems you are already doing this in your code by having an order defined by LinkedHashSet.
The other simple approach is:
If you want an ordered map by keys, you most probably need a TreeMap, insertion into this map maintains the natural ordering of keys and you can construct a treemap from an existing map.
private List<Map<String, String>> sort(List<Map<String,String> result) {
List<Map<String, String>> sortedResult = new LinkedList<>();
for ( Map<String, String> m : result )
sortedResult.add(new TreeMap(m)));
return sortedResult;
}
BTW, Local variables referenced from a lambda expression must be final
There are a couple of things I would change:
The argument name "result" is misleading. People going over the code quickly will think this is the returned result. I would change it to "unsortedMaps" or something similar
Each Map shouldn't affect the other so instead of result.forEach you could use result.parallelStream().forEach to make every map sorted in it's own thread. You will need to make insertion to list itself thread safe (either surronding "sortedResult.add(sortedMap" with synchronized statment or use a thread-safe list implementation. All this doesn't guarantee improvement in performance. It depends on many variants such as the size of the collections and number of cores. Test it to find out.
There are a lot of details in this function. I would extract the part dealing with each map to a seperate function
Here is the result (didn't test the code so can't gurentee correctness. Needless to say unit-tests are always the way to go):
private List<Map<String, String>> sort(List<Map<String,String>> unsortedMaps, LinkedHashSet<String> keys){
List<Map<String, String>> sortedResult = new LinkedList<>();
unsortedMaps.parallelStream().forEach(map -> {
Map<String, String> sortedMap = getSortedMap(keys, map);
synchronized (sortedResult) {
sortedResult.add(sortedMap);
}
});
return sortedResult;
}
private Map<String, String> getSortedMap(LinkedHashSet<String> keys, Map<String, String> map) {
Map<String, String> sortedMap = new LinkedHashMap<>();
keys.forEach(key -> {
sortedMap.put(key, map.get(key));
});
return sortedMap;
}
To complete SomeDude answer, if the natural order isn't enough for your need, you can try to specify a Comparator to the TreeMap :
private List<Map<String, String>> sort(List<Map<String,String>> mapList, Set<String> keys){
List<String> keysList = new ArrayList<>(keys);
return mapList.stream().map(map -> copyAndReOrderMap(map, keysList)).collect(Collectors.toList());
}
private Map<String, String> copyAndReOrderMap(Map<String, String> map, List<String> keysList) {
Map<String, String> orderedMap = new TreeMap<>((key1, key2) -> Integer.compare(keysList.indexOf(key1), keysList.indexOf(key2)));
orderedMap.putAll(map);
return orderedMap;
}
NB: Unless you deal with very large maps, i don't see why you would want to sort each map in a separate Thread.

How to sort map of JSONObject

I have a map of JSONObject and Integer. I want to sort it in an incremental order using its values, here is what I've done so far:
Map<JSONObject, Integer> unsortedMap = new HashMap<>();
unsortedMap.put(jsonObject2.getJSONObject(key),key1);
Are you sure you want to use an Object as a key in a hashmap? It's normal practice to use immutable values for keys. The slightest change in any of the elements of the JSONObject will change the hash value and you will be unable to get your info back out of the map.
What is the integer value of your map?
Only a suggestion but you may want to check out the Java API for collection and see if there is anything that better suits your needs. Java Collection API
In the past I have wanted a sorted list with no duplicates. I had to first write to a TreeMap and then write to a SortedSet to get the result I wanted. Not code efficient, but I couldn't achieve what I wanted any other way.
Not sure if this is the best option but could help:
public static Map<String, Integer> SortByKey(Map<String, Integer> map)
{
ArrayList<String> sortedKeys =
new ArrayList<String>(map.keySet());
Collections.sort(sortedKeys);
Map<String, Integer> sortedMap = new HashMap<>();
for (String x : sortedKeys)
sortedMap.put(map.get(x), Integer.parseInt(x));
return sortedMap;
}

How sort an ArrayList of HashMaps holding several key-value pairs each?

I need to call an external API with an ArrayList of HashMaps holding several predefined key-value pairs each. An example:
ArrayList<HashMap<String, String>> arrayListHashMap = new ArrayList<HashMap<String, String>>();
{
HashMap hashMap = new HashMap<String, String>();
hashMap.put("key", "A key");
hashMap.put("value", "B value");
arrayListHashMap.add(hashMap);
}
{
HashMap hashMap = new HashMap<String, String>();
hashMap.put("key", "B key");
hashMap.put("value", "A value");
arrayListHashMap.add(hashMap);
}
Now I need to sort this construct on the contents of the "value" key. This sort would result in the "key=B key/value=A value" entry as the first one in the arrayListHashMap.
Any help is highly appreciated.
HJW
You need to implement a Comparator<HashMap<String, String>> or more generally Comparator<Map<String, String>> which just extracts the value assocated with the value key, then use Collections.sort. Sample code (with generalization for whatever key you want to sort on):
class MapComparator implements Comparator<Map<String, String>>
{
private final String key;
public MapComparator(String key)
{
this.key = key;
}
public int compare(Map<String, String> first,
Map<String, String> second)
{
// TODO: Null checking, both for maps and values
String firstValue = first.get(key);
String secondValue = second.get(key);
return firstValue.compareTo(secondValue);
}
}
...
Collections.sort(arrayListHashMap, new MapComparator("value"));
You can use the below solution to achieve it:
arrayListHashMap.sort(Comparator.comparing(m -> m.get("value"), Comparator.nullsLast(Comparator.naturalOrder())));
(This is not an answer to the asked question - Jon did this already -, but the comment field is too small for this.)
Your data structure looks like you misunderstood the key-value structure of maps (and Hash maps in your example).
A Map can contain any number of keys, and for each key also a value. A pair of key and value is given by a Map.Entry (which can be obtained by the entrySet() method of the map). If you then want to sort by key, simply use a SortedMap (like TreeMap) instead of the usual HashMap.
You are emulating the individual entries by a HashMap each, then putting them all in a ArrayList ... :-/
Here what I would have done in your example:
Map<String, String> map = new TreeMap<String, String>();
map.put("B key", "B value");
map.put("A key", "B value");
System.out.println(map); // already sorted

storing hashMap in a hashMap

i am reading data from a text file and want to store HashMap in another HashMap..
HashMap<string,HashMap<string,value>>
how to store data and retrieve it?
any sample code will be appreciated...
thank u
Example:
Creating and populating the maps
Map<String, Map<String, Value>> outerMap = new HashMap<String, HashMap<String, Value>>();
Map<String, Value> innerMap = new HashMap<String, Value>();
innerMap.put("innerKey", new Value());
Storing a map
outerMap.put("key", innerMap);
Retrieving a map and its values
Map<String, Value> map = outerMap.get("key");
Value value = map.get("innerKey");
Creating two Simple Hashmaps: InnerMap and OuterMap
HashMap<String, HashMap<String, String>> outerMap = new HashMap<String, HashMap<String,String>>();
HashMap<String, String> innerMap = new HashMap<String, String>();
Populating the HashMaps
innerMap.put("InnerKey", "InnerValue");
outerMap.put("OuterKey", innerMap);
Retreiving values from HashMaps
String value = ((HashMap<String, String>)outerMap.get("OuterKey")).get("InnerKey").toString();
System.out.println("Retreived value is : " + value);
You get something that looks like a 2 dimensions HashMap, so to say. Which means you need 2 String to store a value, and also to retrieve one.
You could, for example write a class to wrap that complexity, like that (untested code):
public class HashMap2D<T> {
private HashMap<String,HashMap<String,T>> outerMap;
public HashMap2D() {
outerMap = new HashMap<String,HashMap<String,T>>();
}
public void addElement(String key1, String key2, T value) {
innerMap=outerMap.get(key1);
if (innerMap==null) {
innerMap = new HashMap<String,T>();
outerMap.put(key1,innerMap);
}
innerMap.put(key2,value);
}
public T getElement(String key1, String key2) {
Hashmap innerMap = outerMap.get(key1);
if (innerMap==null) {
return null;
}
return innerMap.get(key2);
}
}
If you want methods to process more than one data at a time, it's more complicated, but follows the same principles.
This will solve the same problem using one map (although, this does not directly answer your question) by flattening two nested maps into one big map, using a double-key.
public class Key2D{
private final String outer;
private final String inner;
public Key2D(String outer, String inner){
this.outer = outer;
this.inner = inner;
}
//include default implementations for
//Object.equals(Object) and Object.hashCode()
//Tip: If you're using Eclipse it can generate
//them for you.
}
Then just create one map with double-key:
Map<Key2D, Value> map = new HashMap<Key2D, Value>();
map.put(new Key2D("outerKey", "innerKey"), "Value");
map.get(new Key2D("outerKey", "innerKey")); // yields "Value"
This gives a shorter solution. Performance wise it's probably about the same. Memory performance is probably slightly better (just guessing, though).
HashMap in HashMap will cause problems in readability especially when it goes beyond two levels. I assume that when you read data from a text file you want to categorize the inputs from rows and columns which should be similar to multi-level categories or category within a category. If you can post the sample data and your intention, I could come up with a Custom class example.
public class Category {
private List<Category> subCategories;
private List<Item> items;
}
The above data structure will help you solve any level of nesting while categorizing data. This example is specific to a store items' classification.

Categories