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}
Related
This is my list.
list = Stream.of(
"06|20|1",
"11|20|2",
"11|20|2",
"07|207|6",
"11|207|2",
"07|207|6",
).collect(Collectors.toList());
I have a hashmap such as:
HashMap<String, HashMap<String, String>> hashMap = new HashMap<>();
HashMap<String, String> newHash = new HashMap<>();
And my code is
for (String line : list) {
String key, value, priority;
key = line.split("\\|", -1)[1];
value = line.split("\\|", -1)[0];
priority = line.split("\\|", -1)[2];
if (hashMap.containsKey(key)) {
HashMap<String, String> getPriority = hashMap.get(key);
Map.Entry<String, String> entry = getPriority.entrySet().iterator().next();
String oldKey = entry.getKey();
String previousPrior = getPriority.get(oldKey);
if (Integer.parseInt(priority) > Integer.parseInt(previousPrior)) {
getPriority.remove(oldKey);
getPriority.put(value,priority);
hashMap.put(key, getPriority);
}
} else {
newHash.put(value, priority);
System.out.println(newhas);
hashMap.put(key, newhas);
}
}
I want to have the have the key with highest priority only such as:
{20={11=2},207={07=6}}
as 11 and 7 has the highest valaues in 20 and 207.
But i am getting all values in the inner hashmap.
How about using streams instead?
Map<String, Map<String, String>> map = list.stream()
.map(line -> line.split("\\|"))
.sorted(Comparator.comparingInt(line -> Integer.parseInt(line[2])))
.collect(Collectors.toMap(
line -> line[1],
line -> Map.of(line[0], line[2]),
(low, high) -> high));
Ideone Demo
For each new key that you insert in your Map variable in the else condition of your code you need to create new HashMap to insert it along with the new key.
What you are doing is using the same newhas variable for all the keys in your Map variable.
So change this
else {
newhas.put(value, priority);
System.out.println(newhas);
Map.put(key, newhas);
}
to
else {
newHas = new HashMap<>();
newhas.put(value, priority);
System.out.println(newhas);
Map.put(key, newhas);
}
Ideone Demo
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);
}
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());
}
}
ı am trying to merge more than one hashmaps also sum the values of same key,
ı want to explain my problem with toy example as follows
HashMap<String, Integer> m = new HashMap<>();
HashMap<String, Integer> m2 = new HashMap<>();
m.put("apple", 2);
m.put("pear", 3);
m2.put("apple", 9);
m2.put("banana", 6);
ı tried putall
m.putAll(m2);
output is as follows
{banana=6, apple=9, pear=3}
but its result is not true for this problem.
ı want to output as
{banana=6, apple=11, pear=3}
how can ı get this result in java?
If you are using Java 8, you can use the new merge method of Map.
m2.forEach((k, v) -> m.merge(k, v, (v1, v2) -> v1 + v2));
This is a very nice use case for Java 8 streams. You can concatentate the streams of entries and then collect them in a new map:
Map<String, Integer> combinedMap = Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.summingInt(Map.Entry::getValue)));
There are lots of nice things about this solution, including being able to make it parallel, expanding to as many maps as you want and being able to trivial filter the maps if required. It also does not require the orginal maps to be mutable.
This method should do it (in Java 5+)
public static <K> Map<K, Integer> mergeAndAdd(Map<K, Integer>... maps) {
Map<K, Integer> result = new HashMap<>();
for (Map<K, Integer> map : maps) {
for (Map.Entry<K, Integer> entry : map.entrySet()) {
K key = entry.getKey();
Integer current = result.get(key);
result.put(key, current == null ? entry.getValue() : entry.getValue() + current);
}
}
return result;
}
Here's my quick and dirty implementation:
import java.util.HashMap;
import java.util.Map;
public class MapMerger {
public static void main(String[] args) {
HashMap<String, Integer> m = new HashMap<>();
HashMap<String, Integer> m2 = new HashMap<>();
m.put("apple", 2);
m.put("pear", 3);
m2.put("apple", 9);
m2.put("banana", 6);
final Map<String, Integer> result = (new MapMerger()).mergeSumOfMaps(m, m2);
System.out.println(result);
}
public Map<String, Integer> mergeSumOfMaps(Map<String, Integer>... maps) {
final Map<String, Integer> resultMap = new HashMap<>();
for (final Map<String, Integer> map : maps) {
for (final String key : map.keySet()) {
final int value;
if (resultMap.containsKey(key)) {
final int existingValue = resultMap.get(key);
value = map.get(key) + existingValue;
}
else {
value = map.get(key);
}
resultMap.put(key, value);
}
}
return resultMap;
}
}
Output:
{banana=6, apple=11, pear=3}
There are some things you should do (like null checking), and I'm not sure if it's the fastest. Also, this is specific to integers. I attempted to make one using generics of the Number class, but you'd need this method for each type (byte, int, short, longer, etc)
ı improve Lucas Ross's code. in stead of enter map by one by in function ı give all maps one times to function with arraylist of hashmap like that
public HashMap<String, Integer> mergeAndAdd(ArrayList<HashMap<String, Integer>> maplist) {
HashMap<String, Integer> result = new HashMap<>();
for (HashMap<String, Integer> map : maplist) {
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer current = result.get(key);
result.put(key, current == null ? entry.getValue() : entry.getValue() + current);
}
}
return result;
}
}
it works too. thanks to everbody
Assume that you have many HashMaps: Map<String,Integer> map1, map2, map3;
Then you can use Java 8 streams:
Map<String,Integer> combinedMap = Stream.of(map1, map2, map3)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.summingInt(Map.Entry::getValue)));
If the key exists, add to it's value. If not insert.
Here is a simple example which merges one map into another:
Foo oldVal = map.get(key);
if oldVal == null
{
map2.put(key, newVal);
}
else
{
map2.put(key, newVal + oldVal);
}
Obviously you have to loop over the first map so you can process all of it's entries but that's trivial.
Something like this should work:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String map1_key = entry.getKey();
int map1_value = entry.getValue();
//check:
if(map2.get(map1_key)!=null){
int map2_value = map2.get(map1_key);
//merge:
map3.put(map1_key,map1_value+map2_value);
}else{
map3.put(map1_key,map1_value);
}
}
for (Map.Entry<String, Integer> entry2 : map2.entrySet()) {
String map2_key = entry2.getKey();
int map2_value = entry2.getValue();
//check:
if(map1.get(map2_key)!=null){
int map1_value = map1.get(map2_key);
//merge:
map3.put(map2_key,map1_value+map2_value);
}else{
map3.put(map2_key,map2_value);
}
}
I have the following maps.
Map<String,String> map1= new HashMap<String, String>(){{
put("no1","123"); put("no2","5434"); put("no5","234");}};
Map<String,String> map1 = new HashMap<String, String>(){{
put("no1","523"); put("no2","234"); put("no3","234");}};
sum(map1, map2);
I want to join them to one, summing up similar keyed values together. What;s the best way I could do it using java 7 or guava libraries ?
expected output
Map<String, String> output = { { "no1" ,"646"}, { "no2", "5668"}, {"no5","234"}, {"no3","234" } }
private static Map<String, String> sum(Map<String, String> map1, Map<String, String> map2) {
Map<String, String> result = new HashMap<String, String>();
result.putAll(map1);
for (String key : map2.keySet()) {
String value = result.get(key);
if (value != null) {
Integer newValue = Integer.valueOf(value) + Integer.valueOf(map2.get(key));
result.put(key, newValue.toString());
} else {
result.put(key, map2.get(key));
}
}
return result;
}
try this
Map<String, List<String>> map3 = new HashMap<String, List<String>>();
for (Entry<String, String> e : map1.entrySet()) {
List<String> list = new ArrayList<String>();
list.add(e.getValue());
String v2 = map2.remove(e.getKey());
if (v2 != null) {
list.add(v2);
}
map3.put(e.getKey(), list);
}
for (Entry<String, String> e : map2.entrySet()) {
map3.put(e.getKey(), new ArrayList<String>(Arrays.asList(e.getValue())));
}
Java 8 introduces Map.merge(K, V, BiFunction), which makes this easy if not particularly concise:
Map<String, String> result = new HashMap<>(map1);
//or just merge into map1 if mutating it is okay
map2.forEach((k, v) -> result.merge(k, v, (a, b) ->
Integer.toString(Integer.parseInt(a) + Integer.parseInt(b))));
If you're doing this repeatedly, you're going to be parsing and creating a lot of strings. If you're generating the maps one at a time, you're best off maintaining a list of strings and only parsing and summing once.
Map<String, List<String>> deferredSum = new HashMap<>();
//for each map
mapN.forEach((k, v) ->
deferredSum.computeIfAbsent(k, x -> new ArrayList<String>()).add(v));
//when you're done
Map<String, String> result = new HashMap<>();
deferredSum.forEach((k, v) -> result.put(k,
Long.toString(v.stream().mapToInt(Integer::parseInt).sum())));
If this summing is a common operation, consider whether using Integer as your value type makes more sense; you can use Integer::sum as the merge function in that case, and maintaining lists of deferred sums would no longer be necessary.
Try this
Map<String,String> map1= new HashMap<String, String>(){{
put("no1","123"); put("no2","5434"); put("no5","234");}};
Map<String,String> map2 = new HashMap<String, String>(){{
put("no1","523"); put("no2","234"); put("no3","234");}};
Map<String,String> newMap=map1;
for(String a:map2.keySet()){
if(newMap.keySet().contains(a)){
newMap.put(a,""+(Integer.parseInt(newMap.get(a))+Integer.parseInt(map2.get(a))));
}
else{
newMap.put(a,map2.get(a));
}
}
for(String k : newMap.keySet()){
System.out.println("key : "+ k + " value : " + newMap.get(k));
}