Java map entry string casting issue - java

I'm making a custom irritator to use in a SortedMap with keys being strings and the values being a count of how many times that string has been read.
When I run it, I get this error:
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map$Entry
at comp2402a1.Part8$1.compare(Part8.java:21)
I can't seem to figure out why I'm getting this casting error. Any help and insight anyone could provide would be really appreciated.
Here is my code:
public static void doIt(BufferedReader r, PrintWriter w) throws IOException {
//Custom comparator
Comparator<Map.Entry<String, Integer>> mapCompare = new Comparator<Map.Entry<String, Integer>>(){
#Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
if (o1.getValue()-o2.getValue() != 0){
return o1.getValue()-o2.getValue();
} else {
return o1.getKey().compareTo(o2.getKey());
}
}
};
//Read lines into a HashMap & count instance #s
HashMap<String, Integer> hMap = new HashMap();
for (String line = r.readLine(); line != null; line = r.readLine()) {
if (hMap.get(line)==null) {
hMap.put(line,1);
w.println("1");
} else {
hMap.put(line, hMap.get(line)+1);
}
}
//Put objects into sorted map w/custom sort and output
SortedMap<String, Integer> sMap = new TreeMap(mapCompare);
sMap.putAll(hMap);
for (Map.Entry<String, Integer> e : sMap.entrySet()){
w.println(e.getKey());
}
}

The error was appearing because I was creating a comparator of type Comparator<Map.Entry<String, Integer>> instead of Comparator<String>.
I fixed it by first creating calling Map.entrySet() on my HashMap, putting that into a list, sorting it, then basing my SortedMap off of that.

Related

sorting hashmap with Collections.sort restarts the sort once every few values [duplicate]

This question already has answers here:
Sort a Map<Key, Value> by values
(64 answers)
Closed 3 years ago.
How are we able to sort a HashMap<key, ArrayList>?
I want to sort on the basis of a value in the ArrayList.
Do you have to use a HashMap? If you only need the Map Interface use a TreeMap
If you want to sort by comparing values in the HashMap. You have to write code to do this, if you want to do it once you can sort the values of your HashMap:
Map<String, Person> people = new HashMap<>();
Person jim = new Person("Jim", 25);
Person scott = new Person("Scott", 28);
Person anna = new Person("Anna", 23);
people.put(jim.getName(), jim);
people.put(scott.getName(), scott);
people.put(anna.getName(), anna);
// not yet sorted
List<Person> peopleByAge = new ArrayList<>(people.values());
Collections.sort(peopleByAge, Comparator.comparing(Person::getAge));
for (Person p : peopleByAge) {
System.out.println(p.getName() + "\t" + p.getAge());
}
If you want to access this sorted list often, then you could insert your elements into a HashMap<TreeSet<Person>>, though the semantics of sets and lists are a bit different.
Sorted List by hasmap keys:
SortedSet<String> keys = new TreeSet<String>(myHashMap.keySet());
Sorted List by hashmap values:
SortedSet<String> values = new TreeSet<String>(myHashMap.values());
In case of duplicated map values:
List<String> mapValues = new ArrayList<String>(myHashMap.values());
Collections.sort(mapValues);
Good Luck!
http://snipplr.com/view/2789/sorting-map-keys-by-comparing-its-values/
get the keys
List keys = new ArrayList(yourMap.keySet());
Sort them
Collections.sort(keys)
print them.
In any case, you can't have sorted values in HashMap (according to API This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time ].
Though you can push all these values to LinkedHashMap, for later use as well.
Seems like you might want a treemap.
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html
You can pass in a custom comparator to it if that applies.
In Java 8:
Comparator<Entry<String, Item>> valueComparator =
(e1, e2) -> e1.getValue().getField().compareTo(e2.getValue().getField());
Map<String, Item> sortedMap =
unsortedMap.entrySet().stream().
sorted(valueComparator).
collect(Collectors.toMap(Entry::getKey, Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
Using Guava:
Map<String, Item> map = ...;
Function<Item, Integer> getField = new Function<Item, Integer>() {
public Integer apply(Item item) {
return item.getField(); // the field to sort on
}
};
comparatorFunction = Functions.compose(getField, Functions.forMap(map));
comparator = Ordering.natural().onResultOf(comparatorFunction);
Map<String, Item> sortedMap = ImmutableSortedMap.copyOf(map, comparator);
Custom compare function which includes functionality for the Turkish alphabet or other different languages than english.
public <K extends Comparable,V extends Comparable> LinkedHashMap<K,V> sortByKeys(LinkedHashMap<K,V> map){
List<K> keys = new LinkedList<K>(map.keySet());
Collections.sort(keys, (Comparator<? super K>) new Comparator<String>() {
#Override
public int compare(String first, String second) {
Collator collator = Collator.getInstance(Locale.getDefault());
//Collator collator = Collator.getInstance(new Locale("tr", "TR"));
return collator.compare(first, second);
}
});
LinkedHashMap<K,V> sortedMap = new LinkedHashMap<K,V>();
for(K key: keys){
sortedMap.put(key, map.get(key));
}
return sortedMap;
}
here is the using example as the following
LinkedHashMap<String, Boolean> ligList = new LinkedHashMap<String, Boolean>();
ligList = sortByKeys(ligList);
Without any more information, it's hard to know exactly what you want. However, when choosing what data structure to use, you need to take into account what you need it for. Hashmaps are not designed for sorting - they are designed for easy retrieval. So in your case, you'd probably have to extract each element from the hashmap, and put them into a data structure more conducive to sorting, such as a heap or a set, and then sort them there.
If you want to combine a Map for efficient retrieval with a SortedMap, you may use the ConcurrentSkipListMap.
Of course, you need the key to be the value used for sorting.
have you considered using a LinkedHashMap<>()..?
public static void main(String[] args) {
Map<Object, Object> handler = new LinkedHashMap<Object, Object>();
handler.put("item", "Value");
handler.put(2, "Movies");
handler.put("isAlive", true);
for (Map.Entry<Object, Object> entrY : handler.entrySet())
System.out.println(entrY.getKey() + ">>" + entrY.getValue());
List<Map.Entry<String, Integer>> entries = new ArrayList<Map.Entry<String, Integer>>();
Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> a,
Map.Entry<String, Integer> b) {
return a.getValue().compareTo(b.getValue());
}
});
}
results into an organized linked object.
item>>Value
2>>Movies
isAlive>>true
check the sorting part picked from here..
I have developed a class which can be used to sort a map on the basis of keys and values. The basic idea is if you have sort a map using keys then create a TreepMap from your Map which will sort the map by keys. And in case of sorting by values create a list from entrySet and sort the list using comparator interface.
Here is the full solution :
public static void main(String[] args) {
Map<String, Integer> unSortedMap = new LinkedHashMap<String, Integer>();
unSortedMap.put("A", 2);
unSortedMap.put("V", 1);
unSortedMap.put("G", 5);
System.out.println("Unsorted Map :\n");
for (Map.Entry<String, Integer> entry : unSortedMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
System.out.println("\n");
System.out.println("Sorting Map Based on Keys :\n");
Map<String, Integer> keySortedMap = new TreeMap<String, Integer>(unSortedMap);
for (Map.Entry<String, Integer> entry : keySortedMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
System.out.println("\n");
System.out.println("Sorting Map Based on Values :\n");
List<Entry<String, Integer>> entryList = new ArrayList<Entry<String, Integer>>(unSortedMap.entrySet());
Collections.sort(entryList, new Comparator<Entry<String, Integer>>() {
#Override
public int compare(Entry<String, Integer> obj1, Entry<String, Integer> obj2) {
return obj1.getValue().compareTo(obj2.getValue());
}
});
unSortedMap.clear();
for (Entry<String, Integer> entry : entryList) {
unSortedMap.put(entry.getKey(), entry.getValue());
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
Code is properly tested :D
Sorting HashMap by Value:
As others have pointed out. HashMaps are for easy lookups if you change that or try to sort inside the map itself you will no longer have O(1) lookup.
The code for your sorting is as follows:
class Obj implements Comparable<Obj>{
String key;
ArrayList<Integer> val;
Obj(String key, ArrayList<Integer> val)
{
this.key=key;
this.val=val;
}
public int compareTo(Obj o)
{
/* Write your sorting logic here.
this.val compared to o.val*/
return 0;
}
}
public void sortByValue(Map<String, ArrayList<>> mp){
ArrayList<Obj> arr=new ArrayList<Obj>();
for(String z:mp.keySet())//Make an object and store your map into the arrayList
{
Obj o=new Obj(z,mp.get(z));
arr.add(o);
}
System.out.println(arr);//Unsorted
Collections.sort(arr);// This sorts based on the conditions you coded in the compareTo function.
System.out.println(arr);//Sorted
}
A proper answer.
HashMap<Integer, Object> map = new HashMap<Integer, Object>();
ArrayList<Integer> sortedKeys = new ArrayList<Integer>(map.keySet());
Collections.sort(sortedKeys, new Comparator<Integer>() {
#Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
});
for (Integer key: sortedKeys) {
//map.get(key);
}
Note that HashMap itself cannot maintain sorting, as other answers have pointed out. It's a hash map, and hashed values are unsorted. You can thus either sort the keys when you need to and then access the values in order, as I demonstrated above, or you can find a different collection to store your data, like an ArrayList of Pairs/Tuples, such as the Pair found in Apache Commons:
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html
Sorting by key:
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("b", "dd");
map.put("c", "cc");
map.put("a", "aa");
map = new TreeMap<>(map);
for (String key : map.keySet()) {
System.out.println(key+"="+map.get(key));
}
}
I developed a fully tested working solution. Hope it helps
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
try {
BufferedReader in = new BufferedReader(new java.io.InputStreamReader (System.in));
String str;
HashMap<Integer, Business> hm = new HashMap<Integer, Business>();
Main m = new Main();
while ((str = in.readLine()) != null) {
StringTokenizer st = new StringTokenizer(str);
int id = Integer.parseInt(st.nextToken()); // first integer
int rating = Integer.parseInt(st.nextToken()); // second
Business a = m.new Business(id, rating);
hm.put(id, a);
List<Business> ranking = new ArrayList<Business>(hm.values());
Collections.sort(ranking, new Comparator<Business>() {
public int compare(Business i1, Business i2) {
return i2.getRating() - i1.getRating();
}
});
for (int k=0;k<ranking.size();k++) {
System.out.println((ranking.get(k).getId() + " " + (ranking.get(k)).getRating()));
}
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public class Business{
Integer id;
Integer rating;
public Business(int id2, int rating2)
{
id=id2;
rating=rating2;
}
public Integer getId()
{
return id;
}
public Integer getRating()
{
return rating;
}
}
}
HashMap doesnt maintain any order, so if you want any kind of ordering, you need to store that in something else, which is a map and can have some kind of ordering, like LinkedHashMap
below is a simple program, by which you can sort by key, value, ascending ,descending ..( if you modify the compactor, you can use any kind of ordering, on keys and values)
package com.edge.collection.map;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class SortMapByKeyValue {
Map<String, Integer> map = new HashMap<String, Integer>();
public static void main(String[] args) {
SortMapByKeyValue smkv = new SortMapByKeyValue();
smkv.createMap();
System.out.println("After sorting by key ascending order......");
smkv.sortByKey(true);
System.out.println("After sorting by key descindeng order......");
smkv.sortByKey(false);
System.out.println("After sorting by value ascending order......");
smkv.sortByValue(true);
System.out.println("After sorting by value descindeng order......");
smkv.sortByValue(false);
}
void createMap() {
map.put("B", 55);
map.put("A", 80);
map.put("D", 20);
map.put("C", 70);
map.put("AC", 70);
map.put("BC", 70);
System.out.println("Before sorting......");
printMap(map);
}
void sortByValue(boolean order) {
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (order) {
return o1.getValue().compareTo(o2.getValue());
} else {
return o2.getValue().compareTo(o1.getValue());
}
}
});
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
printMap(sortedMap);
}
void sortByKey(boolean order) {
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (order) {
return o1.getKey().compareTo(o2.getKey());
} else {
return o2.getKey().compareTo(o1.getKey());
}
}
});
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
printMap(sortedMap);
}
public void printMap(Map<String, Integer> map) {
// System.out.println(map);
for (Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
}
here is the git link
Convert hashmap to a ArrayList with a pair class
Hashmap<Object,Object> items = new HashMap<>();
to
List<Pair<Object,Object>> items = new ArrayList<>();
so you can sort it as you want, or list sorted by adding order.
Sorting HashMap by value in Java:
public class HashMapSortByValue {
public static void main(String[] args) {
HashMap<Long,String> unsortMap = new HashMap<Long,String>();
unsortMap.put(5l,"B");
unsortMap.put(8l,"A");
unsortMap.put(2l, "D");
unsortMap.put(7l,"C" );
System.out.println("Before sorting......");
System.out.println(unsortMap);
HashMap<Long,String> sortedMapAsc = sortByComparator(unsortMap);
System.out.println("After sorting......");
System.out.println(sortedMapAsc);
}
public static HashMap<Long,String> sortByComparator(
HashMap<Long,String> unsortMap) {
List<Map.Entry<Long,String>> list = new LinkedList<Map.Entry<Long,String>>(
unsortMap.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Long,String>> () {
public int compare(Map.Entry<Long,String> o1, Map.Entry<Long,String> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
HashMap<Long,String> sortedMap = new LinkedHashMap<Long,String>();
for (Entry<Long,String> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
}

Java hashmap building <String, Integer>

I am trying to enhance the code on a JAVA project.
an old method was to build a hashmap manually like this - essentially taking parameters from a form a batch of String numbers --
So ConsiderateOfOtherPeoplesFeelings -- would be like "22"
Map<String, Integer> sDMap = new HashMap<String, Integer>();
sDMap.put("ConsiderateOfOtherPeoplesFeelings", BasicUtils.strToIntConversion(ConsiderateOfOtherPeoplesFeelings));
sDMap.put("RestlessOveractiveCannotStayStillForLong", BasicUtils.strToIntConversion(RestlessOveractiveCannotStayStillForLong));
so the map would populate ideally like this
OLD MAP.........{StealsFromHomeSchoolOrElsewhere=2, HasAtLeastOneGoodFriend=0}
-- I am trying to create this same map - with a hashMapBuilder function
public static Map<String, Integer> hashMapBuilder (String[] array){
Map<String, Integer> map = new HashMap<String, Integer>();
for( String element : array ) {
map.put(element.toString(), BasicUtils.strToIntConversion(element));
}
return map;
}
although the response is not correct.
NEW MAP.........{0=0, 1=1, 2=2}
the strToIntConversion looks like this - as it will take a null/string value and convert it into an Integer
public static Integer strToIntConversion(String str){
int number = 0;
try {
if(str != null){
number = Integer.parseInt(str);
}
}
catch (NumberFormatException e) {
number = 0;
}
return number;
}
when I do this it returns {0=0, 1=1, 2=2} --
String[] myStrings = {ConsiderateOfOtherPeoplesFeelings, RestlessOveractiveCannotStayStillForLong, OftenComplainsOfHeadachesStomachachesOrSickness};
Map<String, Integer> newMap = BasicUtils.hashMapBuilder(myStrings);
System.out.println("NEW MAP........."+ newMap);
In the old code you have:
sDMap.put("ConsiderateOfOtherPeoplesFeelings", BasicUtils.strToIntConversion(ConsiderateOfOtherPeoplesFeelings));
This is a string: "ConsiderateOfOtherPeoplesFeelings"
And this is a variable probably holding the numerical valu: ConsiderateOfOtherPeoplesFeelings
so you should be using those variables as well
You could potentially use annotations to make this happen
class MyData {
#RobSearchable String ConsiderateOfOtherPeoplesFeelings;
#RobSearchable String RestlessOveractiveCannotStayStillForLong;
#RobSearchable String StealsFromHomeSchoolOrElsewhere;
}
Later, you could do this
public static Map<String, Integer> hashMapBuilder(MyData data){
Map<String, Integer> map = new HashMap<String, Integer>();
for(Field f : data.getClass().getDeclaredFields()) {
if(f.getAnnotation(RobSearchable.class) != null) {
String element = f.get(data).toString();
map.put(element.toString(), BasicUtils.strToIntConversion(element));
}
}
return map;
}
Now, as you continue to add fields to your data, they will all automatically show up in the map, as long as you annotate them properly.

Finding the Key from Value in Map

So I am having a bit of trouble understanding how to do this. I am building a word counter in Java using Map<String, Integer> where a word is the String and the amount of times that word was said in a .txt document is Integer. This is all working great...but I am trying to develop a part where it will display at the bottom what the top 5 results are ---> what the top 5 map.values() are.
The problem I have run into is after I find the value, I can't get the String with it.
Any suggestions would be very helpful to me.
You need to use the Map.Entry<String, Integer> to get the pair of the key and value.
The values() method returns only values, whereas the keySet() method returns only the keys.
Firstly, you should sort your map, based on values, to get the top five results.
The straightforward approach uses a Comparator. See the answer here for more.
Then you simply get the first five entries of the map.getEntrySet(). It would be easier to use an Iterator for this.
UPDATE:
Set<Entry<String, Integer>> set = wordCount.entrySet();
List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(set);
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
int topResults = 5;
Iterator<Entry<String, Integer>> iter = list.iterator(); //refer the sorted collection
while (iter.hasNext() && topResults > 0 ) {
Map.Entry<String, Integer> entry = iter.next();
System.out.println(entry.getKey() + "->" + entry.getValue());
topResults --;
}
a) Iterate over the map, this way you have both keys and values accessible:
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
// ...
}
b) build a second map for reverse lookup, e.g. Map - note that this is likely not a good idea here as you may have duplicate keys (same number for different words)
c) consider using a bidimap - this is a map which you can query both by key and by value.
I suggest you to override Comparator and build your Map constructor based on it.
Code is showed below:
class ValueComparator implements Comparator {
Map map;
public ValueComparator(Map map) {
this.map = map;
}
public int compare(Object keyA, Object keyB) {
Comparable valueA = (Comparable) map.get(keyA);
Comparable valueB = (Comparable) map.get(keyB);
return valueB.compareTo(valueA);
}
}
public class YourClass{
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 10);
map.put("b", 30);
map.put("c", 50);
map.put("d", 40);
map.put("e", 20);
System.out.println(map);
Map sortedMap = sortByValue(map);
System.out.println(sortedMap);
}
public static Map sortByValue(Map unsortedMap) {
Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
sortedMap.putAll(unsortedMap);
return sortedMap;
}
}

java iterator in a nested map (Map 2D)

I would like to know: how can I iterate through a 2D map? I have a centralMap:
private final Map<String, Map<String, String>> centralMap =
new HashMap<String, Map<String, String>>();
which contains another map:
Map<String,String> nestedMap = new HashMap<String, String>();
as Value, and the second one is created in the "put" method, so that in the constructor, i have just the centralMap. Now i want to redefine this method and to get complete entry of the map (the 2 keys and the value for each element)
public Iterator<Entry> iterator()
How should I proceed? If possible, how can I remove an element through the iterator without having a problem?
Iterators are meant to operate on a collection, such as the keyset of your first map, or the values (which are a collection of maps) of your nested one. You cannot expect the iterator renove method to understand your complex structure.
I would suggest that you build your own class for this, with your own convenience methods that do what you described.
Also, going on a limb here: make sure you didn't just want to have a multimap. If so, have a look, for example, at guava's HashMultimap
You apply the same procedure as if you were iterating over a single map, you just do it twice:
public void printNestedMap(Map<String, Map<String, String>> map)
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a map
System.out.println("Key1: " + pairs.getKey());
//print the inner Map
printMap((Map<String, String>)pairs.getValue());
it.remove(); // avoids a ConcurrentModificationException
}
}
EDIT
It would actually be better to move the iteration over a single map to a different method to be called in this scenario.
public void printMap(Map<String, String>> map)
{
Iterator it = map.entrySet().iterator();
while(it.hasNext())
{
Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a String
System.out.println("Key2: " + pairs.getKey() + " Value2: " + pairs.getValue());
it.remove();
}
}
EDIT 2: Test Program
import java.util.*;
public class TestMap
{
public static void main(String[] args)
{
Map<String, String> innerMap = new HashMap<>();
Map<String, Map<String, String>> outerMap = new HashMap<>();
innerMap.put("Key1", "Val1");
innerMap.put("Key2", "Val2");
innerMap.put("Key3", "Val3");
innerMap.put("Key4", "Val4");
outerMap.put("OuterKey1", innerMap);
printNestedMap(outerMap);
}
public static void printNestedMap(Map<String, Map<String, String>> map)
{
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a map
System.out.println("Key1: " + pairs.getKey());
//print the inner Map
printMap((Map<String, String>)pairs.getValue());
it.remove(); // avoids a ConcurrentModificationException
}
}
public static void printMap(Map<String, String> map)
{
Iterator it = map.entrySet().iterator();
while(it.hasNext())
{
Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a String
System.out.println("Key2: " + pairs.getKey() + " Value2: " + pairs.getValue());
it.remove();
}
}
}
Output:
Key1: OuterKey1
Key2: Key2 Value2: Val2
Key2: Key1 Value2: Val1
Key2: Key4 Value2: Val4
Key2: Key3 Value2: Val3
If you want to get Map.Entry elements containing the two keys and the value, it will really be much more natural to create a class Pair<String, String> that combines the two keys in a single element and use that as the key in a single map rather than nesting maps.
If you do this, your main structure will be a Map<Pair<String, String>, String> and using the Map.entrySet() method will give you a Set<Map.Entry<String, String>, String> from which you can get an iterator that gives approximately what you're after.
If you need to have a Map<String, Map<String, String>> for other reasons, it is also possible to convert this into the structure described above by reasonably simple code, and this might be the most sensible way of getting the information out of it.
Edit Note:
The Pair class described above is essentially the same as Map.Entry, so you could avoid creating a new class for the key by building a Map<Map.Entry<String, String>, String>. I think it makes the code a bit less clear, but it can certainly be made functionally equivalent.
Sample Code
In the code below, I have defined the Pair class as an inner static (for real use, you might want to extract as an independent class), and written a conversion that takes a nested map as you describe, converts it to the form I've suggested, and uses an iterator on the entries of the converted map to print the values.
The iterator could of course be used for other things, and the convert method and Pair class are generic.
import java.util.*;
public class TestMap
{
public static void main(String[] args)
{
Map<String, String> innerMap1 = new HashMap<String, String>();
Map<String, String> innerMap2 = new HashMap<String, String>();
Map<String, Map<String, String>> outerMap = new HashMap<String, Map<String, String>>();
innerMap1.put("InnerKey1", "Val1");
innerMap1.put("InnerKey2", "Val2");
innerMap1.put("InnerKey3", "Val3");
innerMap1.put("InnerKey4", "Val4");
innerMap2.put("InnerKey5", "Val5");
innerMap2.put("InnerKey6", "Val6");
innerMap2.put("InnerKey7", "Val7");
innerMap2.put("InnerKey8", "Val8");
outerMap.put("OuterKey1", innerMap1);
outerMap.put("OuterKey2", innerMap2);
Map<Pair<String, String>, String> convertedMap = convert(outerMap);
for (Map.Entry<Pair<String, String>, String> entry: convertedMap.entrySet()) {
System.out.println(String.format("OuterKey: %s, InnerKey: %s, Value: %s",
entry.getKey().getFirst(),
entry.getKey().getSecond(),
entry.getValue()
));
}
}
private static <K1,K2,V> Map<Pair<K1, K2>,V> convert(Map<K1, Map<K2,V>> nestedMap) {
Map<Pair<K1, K2>, V> result = new HashMap<Pair<K1, K2>, V>();
for (Map.Entry<K1, Map<K2, V>> outerEntry: nestedMap.entrySet()) {
final K1 outerKey = outerEntry.getKey();
for (Map.Entry<K2, V> innerEntry: outerEntry.getValue().entrySet()) {
final K2 innerKey = innerEntry.getKey();
final V value = innerEntry.getValue();
result.put(new Pair<K1, K2>(outerKey, innerKey), value);
}
}
return result;
}
public static class Pair<T1, T2> {
private T1 first;
private T2 second;
public Pair(T1 first, T2 second) {
this.first = first;
this.second = second;
}
public T1 getFirst() {
return first;
}
public T2 getSecond() {
return second;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair pair = (Pair) o;
if (first != null ? !first.equals(pair.first) : pair.first != null) return false;
if (second != null ? !second.equals(pair.second) : pair.second != null) return false;
return true;
}
#Override
public int hashCode() {
int result = first != null ? first.hashCode() : 0;
result = 31 * result + (second != null ? second.hashCode() : 0);
return result;
}
}
}
Note on Usage in context:
In your current code, you have a class with a field centralMap which is the map in your old nested form, and an integer counter for the size of the map.
This containing class has a method for adding entries that looks like this:
#Override
public String put(final String row, final String column, final String value) {
/**
* Second map which is contained by centralMap, that contain Strings as Keys
* and Values.
*/
Map<String, String> nestedMap;
if (centralMap.containsKey(row))
nestedMap = centralMap.get(row);
else
nestedMap = new HashMap<String, String>();
if (!nestedMap.containsKey(column))
counter++;
centralMap.put(row, nestedMap);
return nestedMap.put(column, value);
}
If instead of using the nested map at all, you change this field to a map of the suggested form, this method would become a bit simpler:
#Override
public String put(final String row, final String column, final String value) {
Pair<String, String> key = new Pair(row, column);
if (centralMap.contains(key)
counter++;
centralMap.put(key, value);
}
And you actually wouldn't need the counter anymore, as it will always contain the same value as centralMap.size().
Update:
From edits put in yesterday but now deleted, it's now clear to me (from edit history) that you want to build a single iterator that delegates to all the iterators of the map in correct sequence, and returns a simple structure containing both keys and the value.
This is certainly possible, and if I have time later, I might add some sample code for it. As was noted in another response, the iterator.remove() method may be impossible or unnatural.
Meanwhile, your requirements (as noted a comment on the same other response) is rather similar to what is supplied by guava's Table. That's open source, and looking at it may give you ideas. You can download the source for guava here.
Specifically, in guava's StandardTable, there is an inner class CellIterator, which looks like:
private class CellIterator implements Iterator<Cell<R, C, V>> {
final Iterator<Entry<R, Map<C, V>>> rowIterator
= backingMap.entrySet().iterator();
Entry<R, Map<C, V>> rowEntry;
Iterator<Entry<C, V>> columnIterator
= Iterators.emptyModifiableIterator();
#Override public boolean hasNext() {
return rowIterator.hasNext() || columnIterator.hasNext();
}
#Override public Cell<R, C, V> next() {
if (!columnIterator.hasNext()) {
rowEntry = rowIterator.next();
columnIterator = rowEntry.getValue().entrySet().iterator();
}
Entry<C, V> columnEntry = columnIterator.next();
return Tables.immutableCell(
rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue());
}
#Override public void remove() {
columnIterator.remove();
if (rowEntry.getValue().isEmpty()) {
rowIterator.remove();
}
}
}
You can't just copy this code as it depends on other things in guava, but it shows the basic pattern of what you have to do.

How to sort a HashMap in Java [duplicate]

This question already has answers here:
Sort a Map<Key, Value> by values
(64 answers)
Closed 3 years ago.
How are we able to sort a HashMap<key, ArrayList>?
I want to sort on the basis of a value in the ArrayList.
Do you have to use a HashMap? If you only need the Map Interface use a TreeMap
If you want to sort by comparing values in the HashMap. You have to write code to do this, if you want to do it once you can sort the values of your HashMap:
Map<String, Person> people = new HashMap<>();
Person jim = new Person("Jim", 25);
Person scott = new Person("Scott", 28);
Person anna = new Person("Anna", 23);
people.put(jim.getName(), jim);
people.put(scott.getName(), scott);
people.put(anna.getName(), anna);
// not yet sorted
List<Person> peopleByAge = new ArrayList<>(people.values());
Collections.sort(peopleByAge, Comparator.comparing(Person::getAge));
for (Person p : peopleByAge) {
System.out.println(p.getName() + "\t" + p.getAge());
}
If you want to access this sorted list often, then you could insert your elements into a HashMap<TreeSet<Person>>, though the semantics of sets and lists are a bit different.
Sorted List by hasmap keys:
SortedSet<String> keys = new TreeSet<String>(myHashMap.keySet());
Sorted List by hashmap values:
SortedSet<String> values = new TreeSet<String>(myHashMap.values());
In case of duplicated map values:
List<String> mapValues = new ArrayList<String>(myHashMap.values());
Collections.sort(mapValues);
Good Luck!
http://snipplr.com/view/2789/sorting-map-keys-by-comparing-its-values/
get the keys
List keys = new ArrayList(yourMap.keySet());
Sort them
Collections.sort(keys)
print them.
In any case, you can't have sorted values in HashMap (according to API This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time ].
Though you can push all these values to LinkedHashMap, for later use as well.
Seems like you might want a treemap.
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html
You can pass in a custom comparator to it if that applies.
In Java 8:
Comparator<Entry<String, Item>> valueComparator =
(e1, e2) -> e1.getValue().getField().compareTo(e2.getValue().getField());
Map<String, Item> sortedMap =
unsortedMap.entrySet().stream().
sorted(valueComparator).
collect(Collectors.toMap(Entry::getKey, Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
Using Guava:
Map<String, Item> map = ...;
Function<Item, Integer> getField = new Function<Item, Integer>() {
public Integer apply(Item item) {
return item.getField(); // the field to sort on
}
};
comparatorFunction = Functions.compose(getField, Functions.forMap(map));
comparator = Ordering.natural().onResultOf(comparatorFunction);
Map<String, Item> sortedMap = ImmutableSortedMap.copyOf(map, comparator);
Custom compare function which includes functionality for the Turkish alphabet or other different languages than english.
public <K extends Comparable,V extends Comparable> LinkedHashMap<K,V> sortByKeys(LinkedHashMap<K,V> map){
List<K> keys = new LinkedList<K>(map.keySet());
Collections.sort(keys, (Comparator<? super K>) new Comparator<String>() {
#Override
public int compare(String first, String second) {
Collator collator = Collator.getInstance(Locale.getDefault());
//Collator collator = Collator.getInstance(new Locale("tr", "TR"));
return collator.compare(first, second);
}
});
LinkedHashMap<K,V> sortedMap = new LinkedHashMap<K,V>();
for(K key: keys){
sortedMap.put(key, map.get(key));
}
return sortedMap;
}
here is the using example as the following
LinkedHashMap<String, Boolean> ligList = new LinkedHashMap<String, Boolean>();
ligList = sortByKeys(ligList);
Without any more information, it's hard to know exactly what you want. However, when choosing what data structure to use, you need to take into account what you need it for. Hashmaps are not designed for sorting - they are designed for easy retrieval. So in your case, you'd probably have to extract each element from the hashmap, and put them into a data structure more conducive to sorting, such as a heap or a set, and then sort them there.
If you want to combine a Map for efficient retrieval with a SortedMap, you may use the ConcurrentSkipListMap.
Of course, you need the key to be the value used for sorting.
have you considered using a LinkedHashMap<>()..?
public static void main(String[] args) {
Map<Object, Object> handler = new LinkedHashMap<Object, Object>();
handler.put("item", "Value");
handler.put(2, "Movies");
handler.put("isAlive", true);
for (Map.Entry<Object, Object> entrY : handler.entrySet())
System.out.println(entrY.getKey() + ">>" + entrY.getValue());
List<Map.Entry<String, Integer>> entries = new ArrayList<Map.Entry<String, Integer>>();
Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> a,
Map.Entry<String, Integer> b) {
return a.getValue().compareTo(b.getValue());
}
});
}
results into an organized linked object.
item>>Value
2>>Movies
isAlive>>true
check the sorting part picked from here..
I have developed a class which can be used to sort a map on the basis of keys and values. The basic idea is if you have sort a map using keys then create a TreepMap from your Map which will sort the map by keys. And in case of sorting by values create a list from entrySet and sort the list using comparator interface.
Here is the full solution :
public static void main(String[] args) {
Map<String, Integer> unSortedMap = new LinkedHashMap<String, Integer>();
unSortedMap.put("A", 2);
unSortedMap.put("V", 1);
unSortedMap.put("G", 5);
System.out.println("Unsorted Map :\n");
for (Map.Entry<String, Integer> entry : unSortedMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
System.out.println("\n");
System.out.println("Sorting Map Based on Keys :\n");
Map<String, Integer> keySortedMap = new TreeMap<String, Integer>(unSortedMap);
for (Map.Entry<String, Integer> entry : keySortedMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
System.out.println("\n");
System.out.println("Sorting Map Based on Values :\n");
List<Entry<String, Integer>> entryList = new ArrayList<Entry<String, Integer>>(unSortedMap.entrySet());
Collections.sort(entryList, new Comparator<Entry<String, Integer>>() {
#Override
public int compare(Entry<String, Integer> obj1, Entry<String, Integer> obj2) {
return obj1.getValue().compareTo(obj2.getValue());
}
});
unSortedMap.clear();
for (Entry<String, Integer> entry : entryList) {
unSortedMap.put(entry.getKey(), entry.getValue());
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
Code is properly tested :D
Sorting HashMap by Value:
As others have pointed out. HashMaps are for easy lookups if you change that or try to sort inside the map itself you will no longer have O(1) lookup.
The code for your sorting is as follows:
class Obj implements Comparable<Obj>{
String key;
ArrayList<Integer> val;
Obj(String key, ArrayList<Integer> val)
{
this.key=key;
this.val=val;
}
public int compareTo(Obj o)
{
/* Write your sorting logic here.
this.val compared to o.val*/
return 0;
}
}
public void sortByValue(Map<String, ArrayList<>> mp){
ArrayList<Obj> arr=new ArrayList<Obj>();
for(String z:mp.keySet())//Make an object and store your map into the arrayList
{
Obj o=new Obj(z,mp.get(z));
arr.add(o);
}
System.out.println(arr);//Unsorted
Collections.sort(arr);// This sorts based on the conditions you coded in the compareTo function.
System.out.println(arr);//Sorted
}
A proper answer.
HashMap<Integer, Object> map = new HashMap<Integer, Object>();
ArrayList<Integer> sortedKeys = new ArrayList<Integer>(map.keySet());
Collections.sort(sortedKeys, new Comparator<Integer>() {
#Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
});
for (Integer key: sortedKeys) {
//map.get(key);
}
Note that HashMap itself cannot maintain sorting, as other answers have pointed out. It's a hash map, and hashed values are unsorted. You can thus either sort the keys when you need to and then access the values in order, as I demonstrated above, or you can find a different collection to store your data, like an ArrayList of Pairs/Tuples, such as the Pair found in Apache Commons:
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html
Sorting by key:
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("b", "dd");
map.put("c", "cc");
map.put("a", "aa");
map = new TreeMap<>(map);
for (String key : map.keySet()) {
System.out.println(key+"="+map.get(key));
}
}
I developed a fully tested working solution. Hope it helps
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
try {
BufferedReader in = new BufferedReader(new java.io.InputStreamReader (System.in));
String str;
HashMap<Integer, Business> hm = new HashMap<Integer, Business>();
Main m = new Main();
while ((str = in.readLine()) != null) {
StringTokenizer st = new StringTokenizer(str);
int id = Integer.parseInt(st.nextToken()); // first integer
int rating = Integer.parseInt(st.nextToken()); // second
Business a = m.new Business(id, rating);
hm.put(id, a);
List<Business> ranking = new ArrayList<Business>(hm.values());
Collections.sort(ranking, new Comparator<Business>() {
public int compare(Business i1, Business i2) {
return i2.getRating() - i1.getRating();
}
});
for (int k=0;k<ranking.size();k++) {
System.out.println((ranking.get(k).getId() + " " + (ranking.get(k)).getRating()));
}
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public class Business{
Integer id;
Integer rating;
public Business(int id2, int rating2)
{
id=id2;
rating=rating2;
}
public Integer getId()
{
return id;
}
public Integer getRating()
{
return rating;
}
}
}
HashMap doesnt maintain any order, so if you want any kind of ordering, you need to store that in something else, which is a map and can have some kind of ordering, like LinkedHashMap
below is a simple program, by which you can sort by key, value, ascending ,descending ..( if you modify the compactor, you can use any kind of ordering, on keys and values)
package com.edge.collection.map;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class SortMapByKeyValue {
Map<String, Integer> map = new HashMap<String, Integer>();
public static void main(String[] args) {
SortMapByKeyValue smkv = new SortMapByKeyValue();
smkv.createMap();
System.out.println("After sorting by key ascending order......");
smkv.sortByKey(true);
System.out.println("After sorting by key descindeng order......");
smkv.sortByKey(false);
System.out.println("After sorting by value ascending order......");
smkv.sortByValue(true);
System.out.println("After sorting by value descindeng order......");
smkv.sortByValue(false);
}
void createMap() {
map.put("B", 55);
map.put("A", 80);
map.put("D", 20);
map.put("C", 70);
map.put("AC", 70);
map.put("BC", 70);
System.out.println("Before sorting......");
printMap(map);
}
void sortByValue(boolean order) {
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (order) {
return o1.getValue().compareTo(o2.getValue());
} else {
return o2.getValue().compareTo(o1.getValue());
}
}
});
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
printMap(sortedMap);
}
void sortByKey(boolean order) {
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (order) {
return o1.getKey().compareTo(o2.getKey());
} else {
return o2.getKey().compareTo(o1.getKey());
}
}
});
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
printMap(sortedMap);
}
public void printMap(Map<String, Integer> map) {
// System.out.println(map);
for (Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
}
here is the git link
Convert hashmap to a ArrayList with a pair class
Hashmap<Object,Object> items = new HashMap<>();
to
List<Pair<Object,Object>> items = new ArrayList<>();
so you can sort it as you want, or list sorted by adding order.
Sorting HashMap by value in Java:
public class HashMapSortByValue {
public static void main(String[] args) {
HashMap<Long,String> unsortMap = new HashMap<Long,String>();
unsortMap.put(5l,"B");
unsortMap.put(8l,"A");
unsortMap.put(2l, "D");
unsortMap.put(7l,"C" );
System.out.println("Before sorting......");
System.out.println(unsortMap);
HashMap<Long,String> sortedMapAsc = sortByComparator(unsortMap);
System.out.println("After sorting......");
System.out.println(sortedMapAsc);
}
public static HashMap<Long,String> sortByComparator(
HashMap<Long,String> unsortMap) {
List<Map.Entry<Long,String>> list = new LinkedList<Map.Entry<Long,String>>(
unsortMap.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Long,String>> () {
public int compare(Map.Entry<Long,String> o1, Map.Entry<Long,String> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
HashMap<Long,String> sortedMap = new LinkedHashMap<Long,String>();
for (Entry<Long,String> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
}

Categories