Sorting on the basis of Keys - java

I have a collection in the form of key, value pair and I was trying to sort it on the basis of
key itself
the values in the collection is
cd,20
ef,65
ab,28
gh,76
Now as shown the first is key , please advise me the ways by which I can sort it on the basis of key itself,
That is the output that I was looking would be.
ab,28
cd,20
ef,65
gh,76

Just create a TreeMap from the original Map. A TreeMap is sorted according to the natural ordering of the keys, and consequently
for (Map.Entry e : treeMap.entrySet()) {
// generics elided for clarity
will be sorted. From the doc for entrySet():
Returns a Set view of the mappings contained in this map. The set's
iterator returns the entries in ascending key order.
Using entrySet() means you can pull the keys and corresponding values in one operation, rather than have to get the keys, and go back to the map for the value. It's a small optimisation, but worth knowing.

TreeMap<String, Integer> map = new TreeMap<>();
// insert entries:
map.put("ab", 12);
// ...
// insertion order does not matter
for (String key : map.keySet()) {
System.out.println(key + ", " + map.get(key));
}
// will always print in sorted order

Related

What is this Java method doing?

public Map mystery(Map map1, Map map2) {
Map result = new TreeMap();
for (String s1 : map1.keySet()) {
if (map2.containsKey(map1.get(s1))) {
result.put(s1, map2.get(map1.get(s1)));
}
}
return result;
}
map1={bar=1, baz=2, foo=3, mumble=4}; map2={1=earth, 2=wind, 3=air, 4=fire}
For each key in map1 method looks at the corresponding value and of this value exists as a key in map2 than puts it a new TreeMap.
Consider one iteration. map1 has key bar and it's value is 1. Now map2 has 1 as it's key with value earth. So data that is put in new Map is bar:earth and so on..
Also note since resultant map is a TreeMap elements will be stored in Lexicographical order (Since keys are Strings and TreeMap stores elements in sorted order as per keys natural ordering).
It's calculating the composition of the functions map2(map1), along with giving you an impressive number of raw-type warnings.

Accessing a Map via index?

Is it tossibe to aceess a Map<Integer, Integer> via index?
I need to get the second element of the map.
You're using the wrong data structure. If you need to lookup by key, you use a Map. If you need to lookup by index or insertion order, use something that lets you index, like an array or list or linked list.
If you need to lookup by both, then you need to create a composite data structure that tracks both keys and insertion order (implementation would be backed by a Map and one of the above aforementioned data structures).
There's even one built into the framework: LinkedHashMap.
There is no direct way to access a map "via index", but it looks like you want a LinkedHashMap, which provides a predictable iteration order:
... which is normally the order in which keys were inserted into the map (insertion-order). Note that insertion order is not affected if a key is re-inserted into the map. (A key k is reinserted into a map m if m.put(k, v) is invoked when m.containsKey(k) would return true immediately prior to the invocation.)
A definition of index is not applicable to Map, as it's not an ordered collection by default.
You can use a TreeMap, which implements NavigableMap, and then iterate the key set using the navigableKeySet() method.
If you just need to get the second element all the time. Why not use a iterator and then do next ,next.
It will depends of Map implementation, but if you want to retrieve the second inserted element, you can use a LinkedHashMap and then create an iterator on values.
Map<Integer, Integer> map = new LinkedHashMap<Integer, Integer>();
map.put(1, 1);
map.put(2, 2);
Integer value = null;
if (map.size() > 1) {
Iterator<Integer> iterator = map.values().iterator();
for (int i = 0; i < 2; i++) {
value = iterator.next();
}
}
// value contains second element
System.out.println(value);
Map does not store elements in the insertion order. It stores elements into buckets based on the value of the hashCode of the element that is being stored. So no, you cannot get it by index.
Anyways, you could imitate something like this by using the LinkedHashMap implementation of the Map interface, which remembers the insertion order (unlinke the HashMap).
You would have to "hack" with manual index counter and the code would look something like this:
Map<String, String> map= new LinkedHashMap<>();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
int index= 0;
for (String key : map.keySet()) {
if (index++ == 1) {
System.out.println(map.get(key));
}
}
Will print:
"two"
Which is what you want.
You can also use org.apache.commons.collections.map.ListOrderedMap from apache commons-collection. It implements Map and provides some methods from the List interface, like get(int index) and remove(int index).
It uses an ArrayList internally, so performance will be better than iterating on a Map to retrieve a value at specified position.
Not sure if this is any "cleaner", but:
If use LinkedHashMap and u want to retrieve element inserted second following will work
List keys = new ArrayList(map.keySet());
Object obj = map.get(keys.get(1));
//do you staff here

Sorted map not outputting sorted. Do I understand maps.

I have been reading up on maps and understand some of the differences in tree maps and hash, sorted maps. I was trying to get a map to be sorted when outputting it.
What I needed to be able to do was:
Take a text file and read in the content.
Break it into separate words. Use the words as the key and the value as how many times the key occurs in the txt file.
If the word is at the end of a sentence I am to make it a separate key. E.g., my and my. are two separate keys.
My problem is that no matter if I declare it as a tree, hash or sorted map, I can't get it to output/iterate through in an ordered way. I wanted it to output with the highest occurring value first, but I can't even get it to output with the key in any order.
public static Map<String, Integer> createDictionary(String _filename)
{
TreeMap<String, Integer> dictionary = new TreeMap<String, Integer>(); // Changed Hash to _______
try {
FileReader myFileReader=new FileReader(_filename); // File reader stream open
BufferedReader myBuffReader=new BufferedReader(myFileReader);
String str = "\0";
while (str != null) { // While there are still strings in the file
str = myBuffReader.readLine(); // We read a line into the str variable
if (str != null) { // Make sure its not the last line/EOF
// System.out.println(str); // Used for testing.
StringTokenizer myTokenStr=new StringTokenizer(str," \t"); // Create a StringToken obj from the string
while (myTokenStr.hasMoreTokens()) {
String tokStr = myTokenStr.nextToken(); // Each token is put into an individual string
// System.out.println(tokStr);
if (dictionary.containsKey(tokStr)) {
int value = dictionary.get(tokStr); // Add one to the integer value
// dictionary.remove(tokStr); // Was doing this way but just using put method works
// dictionary.put(tokStr, value + 1);
dictionary.put(tokStr, value + 1);
}
else {
dictionary.put(tokStr, 1); // Add the string as the key with an int value of one for the value
}
}
}
}
myBuffReader.close(); // Close stream
myFileReader.close(); // Close stream
}
catch (FileNotFoundException e) {
System.out.println("File Not Found");
}
catch (IOException e) { }
// System.out.println(dictionary.entrySet());
return dictionary;
}
Your map is sorted alphabetically, not by number of occurrences. You need to postprocess the map after the initial parsing. I would suggest:
Parse file into HashMap<String, Integer>
Iterate through HashMap, and add elements to a TreeMap<Integer, Set<String> > (see below).
Output the TreeMap.
You can achieve step 2. by something like:
TreeMap<Integer, Set<String> > treeMap = new TreeMap<Integer, Set<String> > ();
for (Map.Entry<String, Integer> entry: hashMap) {
Set<String> set = treeMap.get(entry.value());
if (set == null) {
set = new TreeSet<String>();
treeMap.put(entry.value(), set);
}
set.add(entry.key());
}
Using TreeSet here sorts the words with same number of occurrences alphabetically, you could use any other Set or List though.
For descending order in step 3.:
for (Map.Entry<Integer, Set<String> > entry: treeMap.descendingMap())
for (String word: entry.getValue())
System.out.println(String.format("%d: %s", entry.getKey(), word));
That should do it.
This is the documentation for TreeMap, lifted from its Javadoc:
public class TreeMap extends AbstractMap
implements NavigableMap, Cloneable, Serializable
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.
In your case, the keys would be strings, and you should expect that iteration will reveal the map to be sorted according to their 'natural order'. Here's an example of the output generated by a TreeMap consisting of String keys and Integer values:
Map<String, Integer> map = new TreeMap<String, Integer>();
map.put("Hello", Integer.valueOf(8));
map.put("Abraham", Integer.valueOf(81));
map.put("Smell", Integer.valueOf(-1));
map.put("Carpet", Integer.valueOf(4));
map.put("Sex", Integer.valueOf(23));
for(String key: map.keySet()) {
System.out.printf("Map entry %s: %d\n", key, map.get(key));
}
Output:
Map entry Abraham: 81
Map entry Carpet: 4
Map entry Hello: 8
Map entry Sex: 23
Map entry Smell: -1
As you can see, iterating over the map's keys produces as ordered result. This order is defined by the natural order of String. Unfortunately, you cannot implement a SortedMap that sorts on values, which is what I believe you want to do. You can however, sort the entries in the Map outside of it. See more details in this other SO post: TreeMap sort by value.
Map is a kind of messy abstraction for this sort of thing, but I'm going to throw out Guava's Multiset as a way to address this use case, as it's expressly designed for "counting occurrences of things."
In particular,
return Multisets.copyHighestCountFirst(HashMultiset.copyOf(listOfWords));
returns a Multiset that iterates over elements in order of descending frequency in listOfWords.
There are many questions on SO, by the way, relating to ordering maps by values instead of keys, but I prefer this solution.

Get 3 highest values from Map<String,String>

I have a Map<String,String> which has entries like "User1","43". Now I want a "Top 3" of the highest values.
It would be easier with a Map<String,Integer>, but due to technical limitations I can just grab the Map as a <String,String>.
What's the most efficient way to convert a <String,String> map to a <String,Int> one and then sort it?
To convert from <String, String> to <String, Integer> you can use:
Map<String, Integer> treemap = new HashMap<String, Integer>();
for (Entry<String, String> entry : entries) {
treemap.put(entry.getKey(), Integer.parseInt(entry.getValue()));
}
However, then you will have to iterate the Map again. If you don't need the whole map, but rather just the top 3, then you can simply iterate the entries and get the top three by comparison.
Or you can reverse the key and value and use a TreeMap<Integer, String> with a Comparator, if you need both the top elements and the whole data.
There are a few ways:
Create SortedMap, e.g. TreeMap with a custom -anonymous- Comparator which performs comparisons by looking up the keys it gets in the compare() method call against the values in the original map.
Populate it with all key/value entries in the original through addAll() method.
Watch the map being sorted by value.
Grab the head/tail (depending on how your comparator sorts)
Similar to above:
Create a TreeSet of keys with a custom comparator as above...
Populate it with the keySet() of your original map.
Grab the head/tail set of the keys.
Create a new Map from those keys and value from the original map...
You could just put the values in a List and sort it:
ArrayList<Integer> highest = new ArrayList<Integer>();
for (String value : map.values()) {
highest.add(Integer.parseInt(value));
}
Collections.sort(highest);
for(int i = highest.size() - 1; i >=0 && i > highest.size()-4; i--){
System.out.println(highest.get(i));
}
If the map is very large it might be better to iterate through it and only select the 3 highest values without sorting the whole list.
You could iterate through the values of the Map (with Map.values()), converting each to an Integer (with Integer.getInteger(String s)), and keeping track of the top 3 you see.
Or, you could do as above but instead of keeping track of the top 3, make a LinkedList and insert each Integer at the correct place (traverse the LinkedList until you find where the Integer should be inserted).

How can I sort the keys of a Map in Java?

This is a very basic question, I'm just not that good with Java. I have a Map and I want to get a list or something of the keys in sorted order so I can iterate over them.
Use a TreeMap, which is an implementation of the SortedMap interface. It presents its keys in sorted order.
Map<String, Object> map = new TreeMap<String, Object>();
/* Add entries to the map in any order. */
...
/* Now, iterate over the map's contents, sorted by key. */
for (Map.Entry<String, ?> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
If you are working with another Map implementation that isn't sorted as you like, you can pass it to the constructor of TreeMap to create a new map with sorted keys.
void process(Map<String, Object> original) {
Map<String, Object> copy = new TreeMap<String, Object>(original);
/* Now use "copy", which will have keys in sorted order. */
...
}
A TreeMap works with any type of key that implements the Comparable interface, putting them in their "natural" order. For keys that aren't Comparable, or whose natural ordering isn't what you need, you can implement your own Comparator and specify that in the constructor.
You have several options. Listed in order of preference:
Use a SortedMap:
SortedMap<whatever> myNewMap = new TreeMap<whatever>(myOldMap);
This is vastly preferable if you want to iterate more than once. It keeps the keys sorted so you don't have to sort them before iterating.
There is no #2.
There is no #3, either.
SortedSet<whatever> keys = new TreeSet<whatever>(myMap.keySet());
List<whatever> keys = new ArrayList<whatever>(myMap.keySet());
Collections.sort(keys);
The last two will get you what you want, but should only be used if you only want to iterate once and then forget the whole thing.
You can create a sorted collection when iterating but it make more sense to have a sorted map in the first place. (As has already been suggested)
All the same, here is how you do it.
Map<String, Object> map;
for(String key: new TreeSet<String>(map.keySet()) {
// accessed in sorted order.
}
Apart from the methods mentioned in other answers, with Java 8 streams, another shorthand to get a sorted key list from a map would be -
List<T> sortedKeys = myMap.keySet().stream().sorted().collect(Collectors.toList());
One could actually get stuff done after .sorted() as well (like using a .map(...) or a .forEach(...)), instead of collecting it in the list and then iterating over the list.

Categories