LinkedHashMap ordered by value - java

I'm trying find a structure similar to a LinkedHashMap that sorts it by its value.
I'll need to be able to update the values.
I'll be checking the order very often, so I need a solution that avoids sorting the Map every time.
something like this:
DynamicSortedMap<String,Integer> map = new DynamicSortedMap<String,Integer>();
map.put("key1",4);
map.put("key2",3);
map.put("key3",6);
System.out.println("Map: "+map);
map.update("key1",1);
System.out.println("Update:"+map);
Output:
Map: {key3=6, key1=4, key2=3}
Update: {key3=6, key2=3, key1=1}
Is there any stucture that allows this?
If not, any ideas of how to do it?
Thanks for your help,

I think you are looking for something like TreeMap, which is sorted by key:
SortedMap<String, Integer> map = new TreeMap<String, Integer>();

Even though LinkedHashMap in fact could be a good base for this it's unfortunately very limited in manipulating the iteration order. I think with apache common-collections your better on.

class SortValueMap extends HashMap<String,Integer>{
#Override
public Set<Entry<String,Integer>> entrySet() {
List<Entry<String,Integer>> entries = new ArrayList<Entry<String,Integer>>(super.entrySet());
Collections.sort(entries, new Comparator<Entry<String,Integer>>(){
#Override
public int compare(Map.Entry<String,Integer> o1, Map.Entry<String,Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}});
return new LinkedHashSet<Entry<String,Integer>>(entries);
}
}
...
SortValueMap map = new SortValueMap();
map.put("key1",4);
map.put("key2",3);
map.put("key3",6);
map.put("key4",1);
System.out.println("Map: "+map);

Related

Priority Data Structures and Finding a winning program using Java 8 Streams

I have a List of programTypes:
List<String> programTypes = {ACF, VCX, IFL}
Note: This is a map hardcoded in code.
Here, I want to attach priorities to these programTypes:
ACF->priority=2, VCX->priority=1, IFL->priority=3
What data structure should I use? Priority Queues?
Also, now I have a list of inputProgramTypes: {ABC, VCX, IFL}
I want the output to be the winningProgramType: VCX
I can code it by iterating on inputProgramTypes and setting the winningProgramType if each next has a priority greater that the set one (Like finding max problem).
But I want to know if I can optimise? And how I can use streams to write code for same to make it look clean? I am new to streams and learning my way through it.
I suggest you use an enum with a parameter constructor.
Such, the method public static Map<ProgramType, Integer> getPrioMap() will elegantly and in a type-safe way return the data structure you need.
public enum ProgramType {
ACF(2), VCX(1), IFL(3);
private int prio;
private ProgramType(int prio) {
this.prio = prio;
}
public Integer getPriority() {
return prio;
}
public static Map<ProgramType, Integer> getPrioMap() {
return List.of(ProgramType.values()).stream()
.collect(Collectors.toMap(e -> e, e -> e.getPriority()));
}
}
Possibly, a simple Map will do fine:
public Map<String, Integer> buildMapOfPriorityProgramTypes() {
Map<String, Integer> priorityProgramTypes = new HashMap<>();
priorityProgramTypes.put("ACF", 2);
priorityProgramTypes.put("VCX", 1);
priorityProgramTypes.put("IFL", 3);
return priorityProgramTypes;
}
public String getTopPriorityType(Map<String, Integer> priorityTypes) {
return priorityTypes.entrySet().stream()
.min(Map.Entry.comparingByValue())
.get().getKey();
}
If you use Java 9 or newer, you may use shorter Map.of:
Map<String, Integer> priorityProgramTypes = Map.of(
"ACF", Integer.valueOf(2),
"VCX", Integer.valueOf(1),
"IFL", Integer.valueOf(3)
);
Use SortedMap interface and its implementation TreeMap:
SortedMap<Integer, List<String>> map = new TreeMap<>();
map.put(2, Collections.singletonList("ACF"));
map.put(1, Collections.singletonList("VCX"));
map.put(3, Collections.singletonList("IFL"));
The advantages are:
The keys are sorted, you can manage the order of them defining a Comparator in the constructor new TreeMap<>(comparator);. The order of processing from the sample above will be:
map.values().forEach(System.out::print);
// [VCX][ACF][IFL]
If more of the strings have the same priority, List<String> as the values of the map are more suitable.
Adding new priority (key) and value (List<String>) to the map will not break the sorted characteristics. For safe adding, I recommend Map::computeIfPresent .

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

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

guava multimap that uses TreeMap not HashMap?

I have something like the following:
final SortedMap<Integer,List<Integer>> m = new TreeMap<Integer,List<Integer>>();
And I'd like to use google-guava to make this a multimap. However I don't see any implementation that provides a SortedMap holding an ArrayList. I only see HashMap+ArrayList implementation (ArrayListMultimap). Does the implementation that I want exist?
Guava has a TreeMultimap that stores both keys and values in sorted order. However, this uses a TreeSet for the values rather than a List so it may not quite be what you want here. In that case, Guava allows you to create a Multimap that works any way you want using one of the Multimaps.new*Multimap methods, such as Multimaps.newListMultimap. To make one that works like you describe, you'd just write this:
Map<Integer, Collection<Integer>> map = Maps.newTreeMap();
ListMultimap<Integer, Integer> m = Multimaps.newListMultimap(map,
new Supplier<List<Integer>>() {
public List<Integer> get() {
return Lists.newArrayList(); // assuming you want to use ArrayList
}
});
Here's how you can create that beast:
Multimap<Integer,Integer> multimap = Multimaps.newListMultimap(
Maps.<Integer, Collection<Integer>>newTreeMap(),
new Supplier<List<Integer>>() {
public List<Integer> get() {
return Lists.newArrayList();
}
});

Categories