I am looking for a way to reordering a hashmap...Similar like Swapping two rows of hashmap with their respective key...
My hashmap is like, before swapping
["key1","value1"];
["key2","value2"];
["key3","value3"];
["key4","value4"];
After swapping key 1 and key 2,
["key4","value4"];
["key2","value2"];
["key3","value3"];
["key1","value1"];
I want to swap two rows along with the key.Is it possible in java?
Not possible with hash map.
HashMap doesn't guarantee the ordering. For that you make look into LinkedHashMap.
Swapping with LinkedHashMap
LinkedHashMap<String, String> oldMap = new LinkedHashMap<>();
oldMap.put("key1", "value1");
oldMap.put("key2", "value2");
oldMap.put("key3", "value3");
oldMap.put("key4", "value4");
System.out.println(oldMap);
ArrayList<String> keySetList = new ArrayList<>();
keySetList.addAll(oldMap.keySet());
Collections.swap(keySetList, 0, 3);
// our output map
LinkedHashMap<String, String> swappedMap = new LinkedHashMap<>();
for(String oldSwappedKey:keySetList) {
swappedMap.put(oldSwappedKey, oldMap.get(oldSwappedKey));
}
System.out.println(swappedMap);
Swapping 1 and 4
Input map:{key1=value1, key2=value2, key3=value3, key4=value4}
Output map:{key4=value4, key2=value2, key3=value3, key1=value1}
Perhaps something like this? Parametrize the keys, but this should end up "swapping" values behind key1 and key2.
private void test(HashMap<MyKey, MyValue> map) {
Set<MyKey> keyset = map.keySet();
MyKey key1 = keyset.get(0);
MyKey key2 = keyset.get(1);
MyValue val1;
MyValue val2;
if (map.containsKey(key1)) {
val1 = map.get(key1);
}
if (map.containsKey(key2)) {
val2 = map.get(key2);
}
if (val2 != null)
map.put(key1, val2);
if (val1 != null)
map.put(key2, val1);
}
Related
I have HashMap < Integer,String> of length 3:
1=>"Value1"
2=>"Value2"
3=>"Value3"
Now I want to decrease all keys by 1(if key>1):
Output:
1=>"Value2"
2=>"Value3"
What I am trying
for (e in hashMap.entries) {
val entry = e as Map.Entry<*, *>
var keyPos = (entry.key as Int)
if (keyPos != -1) {
if (keyPos > 1) {
keyPos = keyPos - 1
if (keyPos != -1) {
hashMap.put(keyPos, entry.value as String?)
}
}
}
}
But its not giving required output.
How to make it work without Concurrency exception.
An alternative is to use mapKeys extension function, which allows you to redefine the key for a map entry:
fun main() {
val originalMap = mapOf(1 to "value1", 2 to "value2", 3 to "value3")
val updatedMap = originalMap
.mapKeys {
if (it.key > 1) {
it.key - 1
} else {
it.key
}
}
println(updatedMap) // prints: {1=value2, 2=value3}
}
Note that this will not update the map in-place, but it will create a new one. Also note that:
In case if any two entries are mapped to the equal keys, the value of the latter one will overwrite the value associated with the former one.
This means that in case two keys are conflicting, in general you can't know which one will "win" (unless you're using a LinkedHashMap, which preserves insertion order).
A more general approach would be to:
decrement all keys
filter out all non-positive keys
This will require 2 full iterations, though, (unless you use Sequences, which are lazily evaluated):
fun main() {
val originalMap = mapOf(1 to "value1", 2 to "value2", 3 to "value3")
val updatedMap = originalMap
.mapKeys {
it.key - 1
}.filter {
it.key > 0
}
println(updatedMap)
}
EDIT: here is the same with Java 7 compatible code (without streams)
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "test1");
hashMap.put(2, "test2");
hashMap.put(3, "test3");
Map<Integer, String> yourNewHashMap = new HashMap<>();
for (final Map.Entry<Integer, String> entry : hashMap.entrySet()) {
if (entry.getKey() != 1) { // make sure index 1 is omitted
yourNewHashMap.put(entry.getKey() - 1, entry.getValue()); // decrease the index for each key/value pair and add it to the new map
}
}
Old answer with streams:
As a new Map Object is okay for you, I would go with the following stream:
comments are inline
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "test1");
hashMap.put(2, "test2");
hashMap.put(3, "test3");
// use this
Map<Integer, String> yourNewHashMap = hashMap.entrySet().stream()
.filter(es -> es.getKey() != 1) // make sure index 1 is omitted
.map(es -> new AbstractMap.SimpleEntry<Integer, String>(es.getKey() - 1, es.getValue())) // decrease the index for each key/value pair
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); // create a new map
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
// Populate the HashMap
map.put(1, "Value1");
map.put(2, "Value2");
map.put(3, "Value3");
System.out.println("Original HashMap: "
+ map);
decreaseAllKeysByOne(map);
}
private static void decreaseAllKeysByOne(HashMap<Integer, String> map) {
// Add your condition (if key>1)
HashMap<Integer, String> newMap = new HashMap<>();
map.remove(1);
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
int i = 1;
while (iterator.hasNext()) {
Map.Entry<Integer, String> entry = iterator.next();
newMap.put(i, entry.getValue());
i++;
}
System.out.println("Modified HashMap: "
+ newMap);
}
Output :
Original HashMap: {1=Value1, 2=Value2, 3=Value3}
Modified HashMap: {1=Value2, 2=Value3}
I have Map<String, List<String>> map now, putting two values inside Map, now when read keyset from map gives in different sequence in different device.
private Map<String, List<String>> map = new HashMap<>();
map.put("First", new ArrayList<String>());
map.put("Second", new ArrayList<String>());
Now, Read keys from this map.
Set<String> keys = map.keySet();
for (int i = 0; i < map.size(); i++) {
Log.d("key", keys.toArray()[i].toString());
}
OUTPUT IN OREO 8.0
D/Key : First
D/Key : Second
OUTPUT in BELOW 8.0
D/Key : Second
D/Key : First
I got a solution until we defined Set as SortedSet ,we getting key sequence in different order.
SortedSet<String> keys = new TreeSet<>(map.keySet());
for (int i = 0; i < map.size(); i++) {
Log.d("key", keys.toArray()[i].toString());
}
You're using the HashMap as the data structure. As in HashMap, the order of insertion is not maintained thus you're getting a random order of the keys. If you want to maintain the order of insertion, simply use a LinkedHashMap. The order in which you put the data is maintained and simply you can iterate over it.
Sample code for LinkedHashMap:
Map<String, String> map = new LinkedHashMap<>();
map.put("key1", "value2");
map.put("key3", "value4");
map.put("key5", "value6");
map.put("key7", "value8");
Set<String> keySet = map.keySet();
for(String st: keySet){
System.out.println(st);
}
for(Map.Entry<String, String> entry : map.entrySet()){
System.out.println(entry.getKey() + " " + entry.getValue());
}
Output:
key1
key3
key5
key7
key1 value2
key3 value4
key5 value6
key7 value8
It has nothing to do with the android OS. The resulting Set of HashMap has no order. However there are Sets with an order e.g. TreeSet.
For instance if I have a map with integer and strings:
Map<Integer, String> myMap = new HashMap<Integer, String>();
This map would contain key values of Integers and values of names.
What I am trying to do is make a new map, that copies all the values (names) from theMap and makes them the keys for the new map. Now the tricky part I can't get, is that I want the values of the new map to be the numbers, but if there are multiple numbers that correspond to the same name I want them to be held in an Set.
Example of new map:
Map<String, Set<Integer>> returnMap = new TreeMap<String, Set<Integer>>();
So if "John" corresponds to 1,2,3,4. I would like the new map to contain a key of "John" with a Set containing 1,2,3,4
Google's Guava library has a nice Multimap class which maps keys to multiple values. If you use it, you can take advantage of a host of helper methods:
SetMultimap<String, Integer> returnMap =
Multimaps.invertFrom(Multimaps.forMap(myMap), TreeMultimap.create());
It's not that tricky :)
Map<Integer, String> map = ... //Your map
Map<String, Set<Integer>> reverseMap = new TreeMap<String, Set<Integer>>();
for(Map.Entry<Integer, String> entry : map.entrySet()) {
Integer key = entry.getKey();
String value = entry.getValue();
Set<Integer> set;
if(reverseMap.containsKey(value)) {
set = reverseMap.get(value);
set.add(key);
} else {
set = new HashSet<Integer>();
set.add(key);
reverseMap.put(value, set);
}
}
I have two HashMap<String,Integer>
How can I sum them easily?
Meaning that for String "a" the key will be sum of (value from Map1 + value from Map2)?
I can iterate every item of Map2 and add manually to Map1.
But thought there might be an easier way?
I prefer summing the Integers into one of the maps. Not creating a new one
Since Java 8 Map contains merge method which requires
key,
new value,
and function which will be used to decide what value to put in map if it already contains our key (decision will be made based on old and new value).
So you could simply use:
map2.forEach((k, v) -> map1.merge(k, v, Integer::sum));
Now your map1 will contain all values from map2 and in case of same keys old value will be added to new value and result will be stored in map.
DEMO:
Map<String, Integer> m1 = new HashMap<>();
m1.put("a", 1);
m1.put("b", 2);
Map<String, Integer> m2 = new HashMap<>();
m2.put("a", 3);
m2.put("c", 10);
System.out.println(m1);
System.out.println(m2);
//iterate over second map and merge its elements into map 1 using
//same key and sum of values
m2.forEach((k, v) -> m1.merge(k, v, Integer::sum));
System.out.println("===========");
System.out.println(m1);
Output:
{a=1, b=2}
{a=3, c=10}
===========
{a=4, b=2, c=10}
in case you like Java 8:
Map<String, Integer> sum(Map<String, Integer>... maps) {
return Stream.of(maps) // Stream<Map<..>>
.map(Map::entrySet) // Stream<Set<Map.Entry<..>>
.flatMap(Collection::stream) // Stream<Map.Entry<..>>
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
Integer::sum));
}
can sum up arbitrary amounts of maps. It turns the array of maps into a Stream<Map.Entry<String, Integer> in the first few lines, then collects all the entries into a new Map while supplying a "merge function" in case of duplicate values.
alternatively something along the lines of
void addToA(HashMap<String, Integer> a, HashMap<String, Integer> b) {
for (Entry<String, Integer> entry : b.entrySet()) {
Integer old = a.get(entry.getKey());
Integer val = entry.getValue();
a.put(entry.getKey(), old != null ? old + val : val);
}
}
Unfortunately, there is no easy way. You need to iterate them manually.
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class HashMapSum {
public static void main(String[] args) {
Map<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("a", 1);
map1.put("b", 2);
map1.put("c", 3);
Map<String, Integer> map2 = new HashMap<String, Integer>();
map2.put("a", 4);
map2.put("b", 5);
map2.put("d", 6);
Set<String> keySet = new HashSet<String>();
keySet.addAll(map1.keySet());
keySet.addAll(map2.keySet());
Map<String, Integer> map3 = new HashMap<String, Integer>();
Integer val1, val2;
for (String key : keySet) {
val1 = map1.get(key);
val1 = (val1 == null ? 0 : val1);
val2 = map2.get(key);
val2 = (val2 == null ? 0 : val2);
map3.put(key, val1 + val2);
}
System.out.println(map3.toString());
}
}
I am getting the below error while using map and performing some remove.How to avoid this ?
Caused by: java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$EntryIterator.next(HashMap.java:834)
at java.util.HashMap$EntryIterator.next(HashMap.java:832)
Map<FormField, Object> ItemMap = domainItem.getValues();
for (Map.Entry<FormField, Object> ValMap : ItemMap.entrySet()) {
List<Field> groupIdList = Mapper.getGroupId(groupFieldId);
for (Field field : groupIdList) {
ItemMap.put(new FormField(field), domainItem.getDomainItemLinkId());
}
ItemMap.remove(ValMap.getKey());
}
Update:
Use Iterator and ConcurrentHashMap to avoid this scenario
Following won't throw exception
Map<Integer, String> map = new ConcurrentHashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
map.put(4, "d");
for (Iterator<Integer> keys = map.keySet().iterator(); keys.hasNext();) {
Integer key = keys.next();
String val = map.get(key);
map.remove(key);
}
or use another map while iterating and at the end copy it to source
for example:
Map<Integer, String> dummy = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
map.put(4, "d");
dummy.putAll(map);
for (Iterator<Integer> keys = dummy.keySet().iterator(); keys.hasNext();) {
Integer key = keys.next();
String val = map.get(key);
map.remove(key);
}
System.out.println(map);
A Map is sorted by the keys in the key-value pairs. When you add or remove elements from the Map while you are iterating through them, the program essentially loses track of "where" in the Map it is.
To get around this, try making a separate, temporary transfer Map. There is also a class called Iterator which might suit your needs.
One way to avoid this issue is to iterate over a copy.
for (Map.Entry<FormField, Object> ValMap :
new HashMap<FormField, Object>(ItemMap).entrySet()) {
can be done without a copy of the map, execute this example and take a look at the code:
public static void main(String[] args)
{
System.out.println("creating map ...");
Map<String, String> dummyMap = new HashMap<>();
while (dummyMap.size() < 10)
{ dummyMap.put(String.valueOf(new Random().nextInt()), String.valueOf(new Random().nextInt())); }
System.out.println("start, map size: " + dummyMap.size() + ", keys=" + dummyMap.keySet());
System.out.print("going to remove: ");
for (Iterator<String> keys = dummyMap.keySet().iterator(); keys.hasNext(); )
{
final String key = keys.next();
// delete map entries per random
if(new Random().nextInt(3)>1)
{
System.out.print(key+" ");
keys.remove();
}
}
System.out.print("\n");
System.out.println("done, map size: " + dummyMap.size() + ", keys=" + dummyMap.keySet());
}
and take a look at this similar question.
HTH,