Related
I am making a method, which takes a provided TreeMap, removes entries where the key is a multiple of keyFilter and the value contains the valueFilter character, and then returns the resulting TreeMap.
This is what I have so far:
public static TreeMap<Integer, String> filterTreeMap(
TreeMap<Integer, String> map, int keyFilter, char valueFilter) {
for (Map.Entry<Integer, String> entry : map.entrySet()) {
int mapKey = entry.getKey();
String mapValue = entry.getValue();
if (mapKey%keyFilter == 0 && mapValue.indexOf(valueFilter) != -1) {
map.remove(mapKey);
}
}
return map;
}
However, under the if condition where I want to delete the entries, I don't know how to delete entries in tree map. As far as I know, there is no existing method that I can use?
Use an Iterator. As the Iterator.remove() Javadoc notes
The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.
Something like
public static TreeMap<Integer, String> filterTreeMap(TreeMap<Integer, String> map,
int keyFilter, char valueFilter) {
Iterator<Map.Entry<Integer, String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Integer, String> entry = iter.next();
int mapKey = entry.getKey();
String mapValue = entry.getValue();
if (mapKey % keyFilter == 0 && mapValue.indexOf(valueFilter) != -1) {
iter.remove();
}
}
return map;
}
It is possible to apply method removeIf to the entry set.
default boolean removeIf(Predicate<? super E> filter)
Removes all of the elements of this collection that satisfy the given predicate. Errors or runtime exceptions thrown during iteration or by the predicate are relayed to the caller.
Implementation Requirements:
The default implementation traverses all elements of the collection using its iterator(). Each matching element is removed using Iterator.remove(). If the collection's iterator does not support removal then an UnsupportedOperationException will be thrown on the first matching element.
Then the method filterTreeMap may have void return type because the input map is modified and this change will be "visible" outside this method.
public static void filterTreeMap(
TreeMap<Integer, String> map, int keyFilter, char valueFilter) {
map.entrySet().removeIf(e ->
e.getKey() % keyFilter == 0
&& e.getValue().indexOf(valueFilter) != -1
);
}
Keys on the map are unique. So, find that keys, and then remove them form the map.
public static TreeMap<Integer, String> filterTreeMap(TreeMap<Integer, String> map,
int keyFilter, char valueFilter) {
Set<Integer> keysToRemove = map.entrySet().stream()
.filter(kv -> kv.getKey() % keyFilter == 0 && kv.getValue().indexOf(valueFilter) != -1) // can be Predicate parameter
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
keysToRemove.forEach(map::remove);
return map; // keep in mind, map is modified here. You might want to return a new map instead
}
Iterate over a copy and you can add/remove just fine:
for (Map.Entry<Integer, String> entry : new LinkedHashMap<Integer,String> (map).entrySet()) {
int mapKey = entry.getKey();
String mapValue = entry.getValue();
if (mapKey%keyFilter == 0 && mapValue.indexOf(valueFilter) != -1) {
map.remove(mapKey);
}
}
It's not even any more lines of code, because the copy is made in-line via the copy constructor. LinkedHashMap was chosen to preserve iteration order (if that matters).
I want to write a comparator that will let me sort a TreeMap by value instead of the default natural ordering.
I tried something like this, but can't find out what went wrong:
import java.util.*;
class treeMap {
public static void main(String[] args) {
System.out.println("the main");
byValue cmp = new byValue();
Map<String, Integer> map = new TreeMap<String, Integer>(cmp);
map.put("de",10);
map.put("ab", 20);
map.put("a",5);
for (Map.Entry<String,Integer> pair: map.entrySet()) {
System.out.println(pair.getKey()+":"+pair.getValue());
}
}
}
class byValue implements Comparator<Map.Entry<String,Integer>> {
public int compare(Map.Entry<String,Integer> e1, Map.Entry<String,Integer> e2) {
if (e1.getValue() < e2.getValue()){
return 1;
} else if (e1.getValue() == e2.getValue()) {
return 0;
} else {
return -1;
}
}
}
I guess what am I asking is: Can I get a Map.Entry passed to the comparator?
You can't have the TreeMap itself sort on the values, since that defies the SortedMap specification:
A Map that further provides a total ordering on its keys.
However, using an external collection, you can always sort Map.entrySet() however you wish, either by keys, values, or even a combination(!!) of the two.
Here's a generic method that returns a SortedSet of Map.Entry, given a Map whose values are Comparable:
static <K,V extends Comparable<? super V>>
SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
return res != 0 ? res : 1;
}
}
);
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
Now you can do the following:
Map<String,Integer> map = new TreeMap<String,Integer>();
map.put("A", 3);
map.put("B", 2);
map.put("C", 1);
System.out.println(map);
// prints "{A=3, B=2, C=1}"
System.out.println(entriesSortedByValues(map));
// prints "[C=1, B=2, A=3]"
Note that funky stuff will happen if you try to modify either the SortedSet itself, or the Map.Entry within, because this is no longer a "view" of the original map like entrySet() is.
Generally speaking, the need to sort a map's entries by its values is atypical.
Note on == for Integer
Your original comparator compares Integer using ==. This is almost always wrong, since == with Integer operands is a reference equality, not value equality.
System.out.println(new Integer(0) == new Integer(0)); // prints "false"!!!
Related questions
When comparing two Integers in Java does auto-unboxing occur? (NO!!!)
Is it guaranteed that new Integer(i) == i in Java? (YES!!!)
polygenelubricants answer is almost perfect. It has one important bug though. It will not handle map entries where the values are the same.
This code:...
Map<String, Integer> nonSortedMap = new HashMap<String, Integer>();
nonSortedMap.put("ape", 1);
nonSortedMap.put("pig", 3);
nonSortedMap.put("cow", 1);
nonSortedMap.put("frog", 2);
for (Entry<String, Integer> entry : entriesSortedByValues(nonSortedMap)) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
Would output:
ape:1
frog:2
pig:3
Note how our cow dissapeared as it shared the value "1" with our ape :O!
This modification of the code solves that issue:
static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
return res != 0 ? res : 1; // Special fix to preserve items with equal values
}
}
);
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
In Java 8:
LinkedHashMap<Integer, String> sortedMap = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(/* Optional: Comparator.reverseOrder() */))
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
A TreeMap is always sorted by the keys, anything else is impossible. A Comparator merely allows you to control how the keys are sorted.
If you want the sorted values, you have to extract them into a List and sort that.
This can't be done by using a Comparator, as it will always get the key of the map to compare. TreeMap can only sort by the key.
Olof's answer is good, but it needs one more thing before it's perfect. In the comments below his answer, dacwe (correctly) points out that his implementation violates the Compare/Equals contract for Sets. If you try to call contains or remove on an entry that's clearly in the set, the set won't recognize it because of the code that allows entries with equal values to be placed in the set. So, in order to fix this, we need to test for equality between the keys:
static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
new Comparator<Map.Entry<K,V>>() {
#Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
int res = e1.getValue().compareTo(e2.getValue());
if (e1.getKey().equals(e2.getKey())) {
return res; // Code will now handle equality properly
} else {
return res != 0 ? res : 1; // While still adding all entries
}
}
}
);
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
"Note that the ordering maintained by a sorted set (whether or not an explicit comparator is provided) must be consistent with equals if the sorted set is to correctly implement the Set interface... the Set interface is defined in terms of the equals operation, but a sorted set performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the sorted set, equal."
(http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html)
Since we originally overlooked equality in order to force the set to add equal valued entries, now we have to test for equality in the keys in order for the set to actually return the entry you're looking for. This is kinda messy and definitely not how sets were intended to be used - but it works.
I know this post specifically asks for sorting a TreeMap by values, but for those of us that don't really care about implementation but do want a solution that keeps the collection sorted as elements are added, I would appreciate feedback on this TreeSet-based solution. For one, elements are not easily retrieved by key, but for the use case I had at hand (finding the n keys with the lowest values), this was not a requirement.
TreeSet<Map.Entry<Integer, Double>> set = new TreeSet<>(new Comparator<Map.Entry<Integer, Double>>()
{
#Override
public int compare(Map.Entry<Integer, Double> o1, Map.Entry<Integer, Double> o2)
{
int valueComparison = o1.getValue().compareTo(o2.getValue());
return valueComparison == 0 ? o1.getKey().compareTo(o2.getKey()) : valueComparison;
}
});
int key = 5;
double value = 1.0;
set.add(new AbstractMap.SimpleEntry<>(key, value));
A lot of people hear adviced to use List and i prefer to use it as well
here are two methods you need to sort the entries of the Map according to their values.
static final Comparator<Entry<?, Double>> DOUBLE_VALUE_COMPARATOR =
new Comparator<Entry<?, Double>>() {
#Override
public int compare(Entry<?, Double> o1, Entry<?, Double> o2) {
return o1.getValue().compareTo(o2.getValue());
}
};
static final List<Entry<?, Double>> sortHashMapByDoubleValue(HashMap temp)
{
Set<Entry<?, Double>> entryOfMap = temp.entrySet();
List<Entry<?, Double>> entries = new ArrayList<Entry<?, Double>>(entryOfMap);
Collections.sort(entries, DOUBLE_VALUE_COMPARATOR);
return entries;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
TreeMap<String, Integer> initTree = new TreeMap();
initTree.put("D", 0);
initTree.put("C", -3);
initTree.put("A", 43);
initTree.put("B", 32);
System.out.println("Sorted by keys:");
System.out.println(initTree);
List list = new ArrayList(initTree.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
#Override
public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
return e1.getValue().compareTo(e2.getValue());
}
});
System.out.println("Sorted by values:");
System.out.println(list);
}
}
//convert HashMap into List
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
Collections.sort(list, (o1, o2) -> o1.getValue().compareTo(o2.getValue()));
If you want to use a Hash map you can add a condition in Comparator to check by values first & if values are equal perform a sort on keys
HashMap<String , Integer> polpularity = new HashMap<>();
List<String> collect = popularity.entrySet().stream().sorted((t2, t1) -> {
if (t2.getValue() > t1.getValue()) {
return -1;
} else if (t2.getValue() < t1.getValue()) {
return +1;
} else {
return t2.getKey().compareTo(t1.getKey());
}
}).map(entry -> entry.getKey()).collect(Collectors.toList());
If you don't want to take care of the latter condition then use a Treemap which will offer you sorting by itself, this can be done in an elegant single line of code:
TreeMap<String, Integer> popularity = new TreeMap<>();
List<String> collect = popularity.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).map(entry -> entry.getKey()).collect(Collectors.toList());
TreeMap is always sorted by the keys.
If you want TreeMap to be sorted by the values, so you can simply construct it also.
Example:
// the original TreeMap which is sorted by key
Map<String, Integer> map = new TreeMap<>();
map.put("de",10);
map.put("ab", 20);
map.put("a",5);
// expected output:
// {a=5, ab=20, de=10}
System.out.println(map);
// now we will constrcut a new TreeSet which is sorted by values
// [original TreeMap values will be the keys for this new TreeMap]
TreeMap<Integer, String> newTreeMapSortedByValue = new TreeMap();
treeMapmap.forEach((k,v) -> newTreeMapSortedByValue.put(v, k));
// expected output:
// {5=a, 10=de, 20=ab}
System.out.println(newTreeMapSortedByValue);
Only 1 Line Of Code Solution
Normal Order
map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEach(x->{});
Reverse Order
map.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).forEachOrdered(x -> {});
I understand that the Set returned from a Map's keySet() method does not guarantee any particular order.
My question is, does it guarantee the same order over multiple iterations. For example
Map<K,V> map = getMap();
for( K k : map.keySet() )
{
}
...
for( K k : map.keySet() )
{
}
In the above code, assuming that the map is not modified, will the iteration over the keySets be in the same order. Using Sun's jdk15 it does iterate in the same order, but before I depend on this behavior, I'd like to know if all JDKs will do the same.
EDIT
I see from the answers that I cannot depend on it. Too bad. I was hoping to get away with not having to build some new Collection to guarantee my ordering. My code needed to iterate through, do some logic, and then iterate through again with the same ordering. I'll just create a new ArrayList from the keySet which will guarantee order.
You can use a LinkedHashMap if you want a HashMap whose iteration order does not change.
Moreover you should always use it if you iterate through the collection. Iterating over HashMap's entrySet or keySet is much slower than over LinkedHashMap's.
If it is not stated to be guaranteed in the API documentation, then you shouldn't depend on it. The behavior might even change from one release of the JDK to the next, even from the same vendor's JDK.
You could easily get the set and then just sort it yourself, right?
Map is only an interface (rather than a class), which means that the underlying class that implements it (and there are many) could behave differently, and the contract for keySet() in the API does not indicate that consistent iteration is required.
If you are looking at a specific class that implements Map (HashMap, LinkedHashMap, TreeMap, etc) then you could see how it implements the keySet() function to determine what the behaviour would be by checking out the source, you'd have to really take a close look at the algorithm to see if the property you are looking for is preserved (that is, consistent iteration order when the map has not had any insertions/removals between iterations). The source for HashMap, for example, is here (open JDK 6): http://www.docjar.com/html/api/java/util/HashMap.java.html
It could vary widely from one JDK to the next, so i definitely wouldn't rely on it.
That being said, if consistent iteration order is something you really need, you might want to try a LinkedHashMap.
The API for Map does not guarantee any ordering whatsoever, even between multiple invocations of the method on the same object.
In practice I would be very surprised if the iteration order changed for multiple subsequent invocations (assuming the map itself did not change in between) - but you should not (and according to the API cannot) rely on this.
EDIT - if you want to rely on the iteration order being consistent, then you want a SortedMap which provides exactly these guarantees.
Just for fun, I decided to write some code that you can use to guarantee a random order each time. This is useful so that you can catch cases where you are depending on the order but you should not be. If you want to depend on the order, than as others have said, you should use a SortedMap. If you just use a Map and happen to rely on the order then using the following RandomIterator will catch that. I'd only use it in testing code since it makes use of more memory then not doing it would.
You could also wrap the Map (or the Set) to have them return the RandomeIterator which would then let you use the for-each loop.
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class Main
{
private Main()
{
}
public static void main(final String[] args)
{
final Map<String, String> items;
items = new HashMap<String, String>();
items.put("A", "1");
items.put("B", "2");
items.put("C", "3");
items.put("D", "4");
items.put("E", "5");
items.put("F", "6");
items.put("G", "7");
display(items.keySet().iterator());
System.out.println("---");
display(items.keySet().iterator());
System.out.println("---");
display(new RandomIterator<String>(items.keySet().iterator()));
System.out.println("---");
display(new RandomIterator<String>(items.keySet().iterator()));
System.out.println("---");
}
private static <T> void display(final Iterator<T> iterator)
{
while(iterator.hasNext())
{
final T item;
item = iterator.next();
System.out.println(item);
}
}
}
class RandomIterator<T>
implements Iterator<T>
{
private final Iterator<T> iterator;
public RandomIterator(final Iterator<T> i)
{
final List<T> items;
items = new ArrayList<T>();
while(i.hasNext())
{
final T item;
item = i.next();
items.add(item);
}
Collections.shuffle(items);
iterator = items.iterator();
}
public boolean hasNext()
{
return (iterator.hasNext());
}
public T next()
{
return (iterator.next());
}
public void remove()
{
iterator.remove();
}
}
I agree with LinkedHashMap thing. Just putting my findings and experience while I was facing the problem when I was trying to sort HashMap by keys.
My code to create HashMap:
HashMap<Integer, String> map;
#Before
public void initData() {
map = new HashMap<>();
map.put(55, "John");
map.put(22, "Apple");
map.put(66, "Earl");
map.put(77, "Pearl");
map.put(12, "George");
map.put(6, "Rocky");
}
I have a function showMap which prints entries of map:
public void showMap (Map<Integer, String> map1) {
for (Map.Entry<Integer, String> entry: map1.entrySet()) {
System.out.println("[Key: "+entry.getKey()+ " , "+"Value: "+entry.getValue() +"] ");
}
}
Now when I print the map before sorting, it prints following sequence:
Map before sorting :
[Key: 66 , Value: Earl]
[Key: 22 , Value: Apple]
[Key: 6 , Value: Rocky]
[Key: 55 , Value: John]
[Key: 12 , Value: George]
[Key: 77 , Value: Pearl]
Which is basically different than the order in which map keys were put.
Now When I sort it with map keys:
List<Map.Entry<Integer, String>> entries = new ArrayList<>(map.entrySet());
Collections.sort(entries, new Comparator<Entry<Integer, String>>() {
#Override
public int compare(Entry<Integer, String> o1, Entry<Integer, String> o2) {
return o1.getKey().compareTo(o2.getKey());
}
});
HashMap<Integer, String> sortedMap = new LinkedHashMap<>();
for (Map.Entry<Integer, String> entry : entries) {
System.out.println("Putting key:"+entry.getKey());
sortedMap.put(entry.getKey(), entry.getValue());
}
System.out.println("Map after sorting:");
showMap(sortedMap);
the out put is:
Sorting by keys :
Putting key:6
Putting key:12
Putting key:22
Putting key:55
Putting key:66
Putting key:77
Map after sorting:
[Key: 66 , Value: Earl]
[Key: 6 , Value: Rocky]
[Key: 22 , Value: Apple]
[Key: 55 , Value: John]
[Key: 12 , Value: George]
[Key: 77 , Value: Pearl]
You can see the difference in order of keys. Sorted order of keys is fine but that of keys of copied map is again in the same order of the earlier map. I dont know if this is valid to say, but for two hashmap with same keys, order of keys is same. This implies to the statement that order of keys is not guaranteed but can be same for two maps with same keys because of inherent nature of key insertion algorithm if HashMap implementation of this JVM version.
Now when I use LinkedHashMap to copy sorted Entries to HashMap, I get desired result (which was natural, but that is not the point. Point is regarding order of keys of HashMap)
HashMap<Integer, String> sortedMap = new LinkedHashMap<>();
for (Map.Entry<Integer, String> entry : entries) {
System.out.println("Putting key:"+entry.getKey());
sortedMap.put(entry.getKey(), entry.getValue());
}
System.out.println("Map after sorting:");
showMap(sortedMap);
Output:
Sorting by keys :
Putting key:6
Putting key:12
Putting key:22
Putting key:55
Putting key:66
Putting key:77
Map after sorting:
[Key: 6 , Value: Rocky]
[Key: 12 , Value: George]
[Key: 22 , Value: Apple]
[Key: 55 , Value: John]
[Key: 66 , Value: Earl]
[Key: 77 , Value: Pearl]
Hashmap does not guarantee that the order of the map will remain constant over time.
It doesn't have to be. A map's keySet function returns a Set and the set's iterator method says this in its documentation:
"Returns an iterator over the elements in this set. The elements are returned in no particular order (unless this set is an instance of some class that provides a guarantee)."
So, unless you are using one of those classes with a guarantee, there is none.
Map is an interface and it does not define in the documentation that order should be the same. That means that you can't rely on the order. But if you control Map implementation returned by the getMap(), then you can use LinkedHashMap or TreeMap and get the same order of keys/values all the time you iterate through them.
tl;dr Yes.
I believe the iteration order for .keySet() and .values() is consistent (Java
8).
Proof 1: We load a HashMap with random keys and random values. We iterate on this HashMap using .keySet() and load the keys and it's corresponding values to a LinkedHashMap (it will preserve the order of the keys and values inserted). Then we compare the .keySet() of both the Maps and .values() of both the Maps. It always comes out to be the same, never fails.
public class Sample3 {
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static SecureRandom rnd = new SecureRandom();
// from here: https://stackoverflow.com/a/157202/8430155
static String randomString(int len){
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
sb.append(AB.charAt(rnd.nextInt(AB.length())));
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
for (int j = 0; j < 10; j++) {
Map<String, String> map = new HashMap<>();
Map<String, String> linkedMap = new LinkedHashMap<>();
for (int i = 0; i < 1000; i++) {
String key = randomString(8);
String value = randomString(8);
map.put(key, value);
}
for (String k : map.keySet()) {
linkedMap.put(k, map.get(k));
}
if (!(map.keySet().toString().equals(linkedMap.keySet().toString()) &&
map.values().toString().equals(linkedMap.values().toString()))) {
// never fails
System.out.println("Failed");
break;
}
}
}
}
Proof 2: From here, the table is an array of Node<K,V> class. We know that iterating an array will give the same result every time.
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
transient Node<K,V>[] table;
The class responsible for .values():
final class Values extends AbstractCollection<V> {
// more code here
public final void forEach(Consumer<? super V> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.value);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
The class responsible for .keySet():
final class KeySet extends AbstractSet<K> {
// more code here
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
Carefully look at both the inner classes. They are pretty much the same except:
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key); <- from KeySet class
// action.accept(e.value); <- the only change from Values class
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
They iterate on the same array table to support .keySet() in KeySet class and .values() in Values class.
Proof 3: this answer also explicitly states - So, yes, keySet(), values(), and entrySet() return values in the order the internal linked list uses.
Therefore, the .keySet() and .values() are consistent.
Logically, if the contract says "no particular order is guaranteed", and since "the order it came out one time" is a particular order, then the answer is no, you can't depend on it coming out the same way twice.
You also can store the Set instance returned by the keySet() method and can use this instance whenever you need the same order.
What would be the fastest way to get the common values from all the sets within an hash map?
I have a
Map<String, Set<String>>
I check for the key and get all the sets that has the given key. But instead of getting all the sets from the hashmap, is there any better way to get the common elements (value) from all the sets?
For example, the hashmap contains,
abc:[ax1,au2,au3]
def:[ax1,aj5]
ijk:[ax1,au2]
I want to extract the ax1 and au2 alone, as they are the most common values from the set.
note: not sure if this is the fastest, but this is one way to do this.
First, write a simple method to extract the frequencies for the Strings occurring across all value sets in the map. Here is a simple implementation:
Map<String, Integer> getFrequencies(Map<String, Set<String>> map) {
Map<String, Integer> frequencies = new HashMap<String, Integer>();
for(String key : map.keySet()) {
for(String element : map.get(key)) {
int count;
if(frequencies.containsKey(element)) {
count = frequencies.get(element);
} else {
count = 1;
}
frequencies.put(element, count + 1);
}
}
return new frequencies;
}
You can simply call this method like this: Map<String, Integer> frequencies = getFrequencies(map)
Second, in order to get the most "common" elements in the frequencies map, you simply sort the entries in the map by using the Comparator interface. It so happens that SO has an excellent community wiki that discusses just that: Sort a Map<Key, Value> by values (Java). The wiki contains multiple interesting solutions to the problem. It might help to go over them.
You can simply implement a class, call it FrequencyMap, as shown below.
Have the class implement the Comparator<String> interface and thus the int compare(String a, String b) method to have the elements of the map sorted in the increasing order of the value Integers.
Third, implement another method, call it getCommon(int threshold) and pass it a threshold value. Any entry in the map that has a frequency value greater than threshold, can be considered "common", and will be returned as a simple List.
class FrequencyMap implements Comparator<String> {
Map<String, Integer> map;
public FrequencyMap(Map<String, Integer> map) {
this.map = map;
}
public int compare(String a, String b) {
if (map.get(a) >= map.get(b)) {
return -1;
} else {
return 1;
} // returning 0 would merge keys
}
public ArrayList<String> getCommon(int threshold) {
ArrayList<String> common = new ArrayList<String>();
for(String key : this.map.keySet()) {
if(this.map.get(key) >= threshold) {
common.add(key);
}
}
return common;
}
#Override public String toString() {
return this.map.toString();
}
}
So using FrequencyMap class and the getCommon method, it boils down to these few lines of code:
FrequencyMap frequencyMap = new FrequencyMap(frequencies);
System.out.println(frequencyMap.getCommon(2));
System.out.println(frequencyMap.getCommon(3));
System.out.println(frequencyMap.getCommon(4));
For the sample input in your question this is the o/p that you get:
// common values
[ax1, au6, au3, au2]
[ax1, au2]
[ax1]
Also, here is a gist containing the code i whipped up for this question: https://gist.github.com/VijayKrishna/5973268
How to move a particular HashMap entry to Last position?
For Example, I have HashMap values like this:
HashMap<String,Integer> map = new HashMap<String,Integer>();
map= {Not-Specified 1, test 2, testtest 3};
"Not-Specified" may come in any position. it may come first or in the middle of the map. But i want to move the "Not-Specified" to the last position.
How can I do that?
To answer your question in one sentence:
Per default, Maps don't have a last entry, it's not part of their contract.
And a side note: it's good practice to code against interfaces, not the implementation classes (see Effective Java by Joshua Bloch, Chapter 8, Item 52: Refer to objects by their interfaces).
So your declaration should read:
Map<String,Integer> map = new HashMap<String,Integer>();
(All maps share a common contract, so the client need not know what kind of map it is, unless he specifies a sub interface with an extended contract).
Possible Solutions
Sorted Maps:
There is a sub interface SortedMap that extends the map interface with order-based lookup methods and it has a sub interface NavigableMap that extends it even further. The standard implementation of this interface, TreeMap, allows you to sort entries either by natural ordering (if they implement the Comparable interface) or by a supplied Comparator.
You can access the last entry through the lastEntry method:
NavigableMap<String,Integer> map = new TreeMap<String, Integer>();
// add some entries
Entry<String, Integer> lastEntry = map.lastEntry();
Linked maps:
There is also the special case of LinkedHashMap, a HashMap implementation that stores the order in which keys are inserted. There is however no interface to back up this functionality, nor is there a direct way to access the last key. You can only do it through tricks such as using a List in between:
Map<String,String> map = new LinkedHashMap<String, Integer>();
// add some entries
List<Entry<String,Integer>> entryList =
new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
Entry<String, Integer> lastEntry =
entryList.get(entryList.size()-1);
Proper Solution:
Since you don't control the insertion order, you should go with the NavigableMap interface, i.e. you would write a comparator that positions the Not-Specified entry last.
Here is an example:
final NavigableMap<String,Integer> map =
new TreeMap<String, Integer>(new Comparator<String>() {
public int compare(final String o1, final String o2) {
int result;
if("Not-Specified".equals(o1)) {
result=1;
} else if("Not-Specified".equals(o2)) {
result=-1;
} else {
result =o1.compareTo(o2);
}
return result;
}
});
map.put("test", Integer.valueOf(2));
map.put("Not-Specified", Integer.valueOf(1));
map.put("testtest", Integer.valueOf(3));
final Entry<String, Integer> lastEntry = map.lastEntry();
System.out.println("Last key: "+lastEntry.getKey()
+ ", last value: "+lastEntry.getValue());
Output:
Last key: Not-Specified, last value: 1
Solution using HashMap:
If you must rely on HashMaps, there is still a solution, using a) a modified version of the above comparator, b) a List initialized with the Map's entrySet and c) the Collections.sort() helper method:
final Map<String, Integer> map = new HashMap<String, Integer>();
map.put("test", Integer.valueOf(2));
map.put("Not-Specified", Integer.valueOf(1));
map.put("testtest", Integer.valueOf(3));
final List<Entry<String, Integer>> entries =
new ArrayList<Entry<String, Integer>>(map.entrySet());
Collections.sort(entries, new Comparator<Entry<String, Integer>>(){
public int compareKeys(final String o1, final String o2){
int result;
if("Not-Specified".equals(o1)){
result = 1;
} else if("Not-Specified".equals(o2)){
result = -1;
} else{
result = o1.compareTo(o2);
}
return result;
}
#Override
public int compare(final Entry<String, Integer> o1,
final Entry<String, Integer> o2){
return this.compareKeys(o1.getKey(), o2.getKey());
}
});
final Entry<String, Integer> lastEntry =
entries.get(entries.size() - 1);
System.out.println("Last key: " + lastEntry.getKey() + ", last value: "
+ lastEntry.getValue());
}
Output:
Last key: Not-Specified, last value: 1
HashMap doesn't have "the last position", as it is not sorted.
You may use other Map which implements java.util.SortedMap, most popular one is TreeMap.
A SortedMap is the logical/best choice, however another option is to use a LinkedHashMap which maintains two order modes, most-recently-added goes last, and most-recently-accessed goes last. See the Javadocs for more details.
When using numbers as the key, I suppose you could also try this:
Map<Long, String> map = new HashMap<>();
map.put(4L, "The First");
map.put(6L, "The Second");
map.put(11L, "The Last");
long lastKey = 0;
//you entered Map<Long, String> entry
for (Map.Entry<Long, String> entry : map.entrySet()) {
lastKey = entry.getKey();
}
System.out.println(lastKey); // 11
move does not make sense for a hashmap since its a dictionary with a hashcode for bucketing based on key and then a linked list for colliding hashcodes resolved via equals.
Use a TreeMap for sorted maps and then pass in a custom comparator.
In such scenario last used key is usually known so it can be used for accessing last value (inserted with the one):
class PostIndexData {
String _office_name;
Boolean _isGov;
public PostIndexData(String name, Boolean gov) {
_office_name = name;
_isGov = gov;
}
}
//-----------------------
class KgpData {
String _postIndex;
PostIndexData _postIndexData;
public KgpData(String postIndex, PostIndexData postIndexData) {
_postIndex = postIndex;
_postIndexData = postIndexData;;
}
}
public class Office2ASMPro {
private HashMap<String,PostIndexData> _postIndexMap = new HashMap<>();
private HashMap<String,KgpData> _kgpMap = new HashMap<>();
...
private void addOffice(String kgp, String postIndex, String officeName, Boolean gov) {
if (_postIndexMap.get(postIndex) == null) {
_postIndexMap.put(postIndex, new PostIndexData(officeName, gov));
}
_kgpMap.put( kgp, new KgpData(postIndex, _postIndexMap.get(postIndex)) );
}
Find missing all elements from array
int[] array = {3,5,7,8,2,1,32,5,7,9,30,5};
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int i=0;i<array.length;i++) {
map.put(array[i], 1);
}
int maxSize = map.lastKey();
for(int j=0;j<maxSize;j++) {
if(null == map.get(j))
System.out.println("Missing `enter code here`No:"+j);
}