I have a map:
public static Map<String, Integer> playersInArenas = new HashMap<String, Integer>();
How can I search for all strings (in left column) where Integer (right column) is for example 5?
You can use a loop and compare the value on each iteration:
// declaring map
Map<String, Integer> playersInArenas = new HashMap<String, Integer>();
playersInArenas.put("A", 5);
playersInArenas.put("B", 4);
playersInArenas.put("C", 5);
// "searching" strings
for (Entry<String, Integer> e : playersInArenas.entrySet()) {
if (e.getValue() == 5) {
System.out.println(e.getKey());
}
}
Note: Instead of printing the key you could store it, or do whatever you want with it.
try this
playersInArenas.values().retainAll(Collections.singleton(5));
Set<String> strings = playersInArenas.keySet();
If you are using java-8, you could also use the brand new Stream API.
Set<String> set = playersInArenas.entrySet()
.stream()
.filter(e -> e.getValue() == 5)
.map(e -> e.getKey())
.collect(Collectors.toSet());
What it does is:
get a Stream of all the entries of your map
apply a filter to only get the entries that have the value 5
map each entry to its key
collect the result in a Set
You could use a for each loop that iterates through the maps key set:
Map<String, Integer> playersInArenas = new HashMap<String,Integer>();
playersInArenas.put("hello", 5);
playersInArenas.put("Goodbye", 6);
playersInArenas.put("gret", 5);
for(String key : playersInArenas.keySet()){
//checks to see if the value associated with the current key
// is equal to five
if(playersInArenas.get(key) == 5){
System.out.println(key);
}
Related
For example we have
Map<String, Integer> map = new HashMap<>();
map.put("fragments", 5);
map.put("motes", 3);
map.put("shards", 5);
I want to print them like this:
fragments: 5
shards: 5
motes: 3
I would solve this by first putting the values in a TreeMap
Then I would sort the keys based on equal values and put them in a
LinkedHashMap to preserve the order.
Map<String, Integer> map = new TreeMap<>();
map.put("motes", 3);
map.put("shards", 5);
map.put("fragments", 5);
map = map.entrySet().stream().sorted(Comparator.comparing(
Entry<String, Integer>::getValue).reversed()).collect(
LinkedHashMap<String, Integer>::new,
(map1, e) -> map1.put(e.getKey(), e.getValue()),
LinkedHashMap::putAll);
map.entrySet().forEach(System.out::println);
Based on the excellent answer here, consider the following solution:
public static void main(String[] args) {
final Map<String, Integer> originalMap = new HashMap<>();
originalMap.put("fragments", 5);
originalMap.put("motes", 3);
originalMap.put("shards", 5);
final Map<String, Integer> sortedMap = sortByValue(originalMap, false);
sortedMap
.entrySet()
.stream()
.forEach((entry) -> System.out.println(entry.getKey() + " : " + entry.getValue()));
}
private static Map<String, Integer> sortByValue(Map<String, Integer> unsortedMap, final boolean ascending) {
List<Entry<String, Integer>> list = new LinkedList<>(unsortedMap.entrySet());
// Sorting the list based on values
list.sort((o1, o2) -> ascending ? o1.getValue().compareTo(o2.getValue()) == 0
? o1.getKey().compareTo(o2.getKey())
: o1.getValue().compareTo(o2.getValue()) : o2.getValue().compareTo(o1.getValue()) == 0
? o2.getKey().compareTo(o1.getKey())
: o2.getValue().compareTo(o1.getValue()));
return list.stream().collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> b, LinkedHashMap::new));
}
In my project I am using two maps Map<Character, Set<String>>.
map1 - is temporally holding needed values
map2 - is summing all data from map1 after each loop
for example i got:
map2 = (B; Beryllium, Boron, Bromine)
map2 = (H; Hellum, Hydrogen, Hafnium)
now new map1 is:
map1 = (B; Bismuth)
map1 = (O; Oxygen)
In my code adding Oxygen as new entry is ok, but adding new entry for B ends by overraidding existing data in values and leave me only Bismuth.
My code:
while (iterator.hasNext()) {
Set<String> words = new TreeSet<>();
String word = iterator.next();
char[] wordChars = word.toCharArray();
//some code
words.add(word);
map1.put(wordChars[i], words);
}
map2.putAll(map1);
I tought about using .merge but I have no idea how to use it with Sets as values, and I cannot use simple Strings with concat.
You can use Map#merge like this:
Map<String, Set<String>> map1; // [key="B";values=["Beryllium", "Boron", "Bromine"]]
Map<String, Set<String>> map2; // [key="B";values=["Bismuth"] key="I";values=["Iron"]]
for (Entry<String, Set<String>> entry : map2.entrySet()) {
map1.merge(entry.getKey(), entry.getValue(), (s1, s2) -> {s1.addAll(s2); return s1;});
}
//map1 = [key="B";values=["Beryllium", "Boron", "Bromine", "Bismuth"] key="I";values=["Iron"]]
Map::compute is probably what you're looking for. This gives you a way to map any existing value (if there is one), or provide one if not.
For example, in your case something like the following would probably suffice:
oldMap.compute("B", current -> {
if (current == null) {
// No existing entry, so use newMap's one
return newMap.get("B");
} else {
// There was an existing value, so combine the Sets
final Set<String> newValue = new HashSet<>(current);
newValue.addAll(newMap.get("B"));
return newValue;
}
});
There's also MultiValueMap and Multimap from spring and guava respectively (if you're ok bringing in dependencies) which cover this case with less work already.
Temporary map1 will not be needed in this case. Get the set for that character, if null create a new set. Add the word to that set and put in the map:
while (iterator.hasNext()) {
String word = iterator.next();
//some code
Set<String> words = map2.get(word.charAt(0));
if(words == null) {
words = new TreeSet<>();
}
words.add(word);
map2.put(word.charAt(0), words);
}
When using the merge() function, if the specified key is not already associated with a value or the value is null, it associates the key with the given value.
Otherwise, i.e if the key is associated with a value, it replaces the value with the results of the given remapping function. So in order to do not overwrite the old value you must write your remapping function so that it combines the old and new values.
To do so replace this line :
map2.putAll(map1);
with
map1.forEach( (key, value)->{
map2.merge(key, value, (value1,value2) -> Stream.of(value1,value2)
.flatMap(Set::stream)
.collect(Collectors.toSet()));
});
This will iterate over map1 and add echh key which is not present into map2 and associate it with the given value and for each key which is already present it combines the old values and new values.
Alternative you can also work with Map.computeIfPresent and Map.putIfAbsent
map1.forEach( (key, value)->{
map2.computeIfPresent(key, (k,v) -> Stream.of(v,value).flatMap(Set::stream).collect(Collectors.toSet()));
map2.putIfAbsent(key, value);
});
I have this map that has another HashMap inside it. How can I sum the values of the inner maps and compare them ?
Also the maps size changeable. So I'm looking for a solution that works every size of the maps.
{Team2={Alex=0, Tom=20}, Team1={John=0, Ammy=9, Monica=1}, Team3{...}, ...}
values of teams --> {Alex=0, Tom=20}, {John=0, Ammy=9, Monica=1} ...
values of these values is --> {0,20}, {0,9,1}...
I just want to sum this values and find the biggest one.
for(int i = 0 ; i < teamNameList.size() ; i++){
int sum = sum + teams.get(teamNameList.get(i)).values().values();
}
You can stream through entries, calculate total for each entry and collect the entries back into a new map, e.g.:
Map<String, Map<String, Integer>> map = new HashMap<>();
Map<String, Integer> data = new HashMap<>();
data.put("Alex", 10);
data.put("Tom", 20);
data.put("John", 30);
map.put("team1", data);
Map<String, Integer> totals = map.entrySet()
.stream()
.map(e -> new AbstractMap.SimpleEntry<>(e.getKey(), e.getValue().entrySet().stream().mapToInt(Map.Entry::getValue).sum()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(totals);
If you are using java 8, you can use :
long sum = map.values().stream()
.mapToInt(i -> i.values().stream()
.mapToInt(m -> m).sum()).sum();
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);
}
}