Lets consider we have two hashmaps as below:
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("vishal", 10);
map1.put("sachin", 30);
map1.put("vaibhav", 20);
HashMap<String, Integer> map2 = new HashMap<>();
map2.put("Raja", 10);
map2.put("John", 30);
map2.put("Krishna", 20);
The "vaibhav" from map1 and "krishna" from map2 have the same values.
I need to find the keys from both the maps, which have the same values. In this case, "vaibhav" and "Krishna".
Thanks.
Group by values and store keys in list:
Stream.of(map1.entrySet(), map2.entrySet())
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(
Map.Entry::getValue,
Collectors.mapping(
Map.Entry::getKey,
Collectors.toList()
)
));
It will create:
{20=[vaibhav, Krishna], 10=[vishal, Raja], 30=[sachin, John]}
UPDATE
Other approach
Map<Integer, List<String>> collect = new HashMap<>();
map1.entrySet().forEach(e -> collect
.computeIfAbsent(e.getValue(), k -> new ArrayList<>())
.add(e.getKey()));
map2.entrySet().forEach(e -> collect
.computeIfAbsent(e.getValue(), k -> new ArrayList<>())
.add(e.getKey()));
You can improve the time complexity to O(n + m) where n is the size of first map and m is the size of the second map.
We can achieve this by making values as keys and keys as values.
Steps:
Iterate over each map.
Store all current map values in a new map and collect all keys who have that value in a list and put the current value with this list in the new map.
Now, iterate over any of the new map collections and get the common keys and it's respective values for printing.
Snippet:
private static void showCommonValueKeys(HashMap<String, Integer> map1,HashMap<String, Integer> map2){
Map<Integer,List<String>> map1Collect = flipKeyValue(map1);
Map<Integer,List<String>> map2Collect = flipKeyValue(map2);
for(Map.Entry<Integer,List<String>> m : map1Collect.entrySet()){
int key = m.getKey();
if(map2Collect.containsKey(key)){
System.out.println("For value " + key);
System.out.println("First map keys: " + m.getValue().toString());
System.out.println("Second map keys: " + map2Collect.get(key).toString());
System.out.println();
}
}
}
private static Map<Integer,List<String>> flipKeyValue(HashMap<String, Integer> map){
Map<Integer,List<String>> mapCollect = new HashMap<>();
for(Map.Entry<String,Integer> m : map.entrySet()){
String key = m.getKey();
int val = m.getValue();
mapCollect.putIfAbsent(val,new ArrayList<>());
mapCollect.get(val).add(key);
}
return mapCollect;
}
Demo: https://onlinegdb.com/SJdcpbOXU
This can be achieved through two for loops with a complexity of n*m, where n.m is the size of each map.
Map<String, String> map1 = new HashMap<>();
map1.put("santhosh", "1");
map1.put("raja", "2");
map1.put("arun", "3");
Map<String, String> map2 = new HashMap<>();
map2.put("kumar", "1");
map2.put("mani", "1");
map2.put("tony", "3");
for (Map.Entry<String, String> entry1 : map1.entrySet()) {
String key1 = entry1.getKey();
String value1 = entry1.getValue();
for (Map.Entry<String, String> entry2 : map2.entrySet()) {
String key2 = entry2.getKey();
String value2 = entry2.getValue();
if (value1 == value2) {
System.out.println(key1 + " " + key2);
}
}
Thanks.
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
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));
}
There are two Map, first one contains student id and name. second one contains student id and status of 'Pass' or 'Fail'. There is a method which takes two parameters of Map type and returns Map.
//1st Map
Map<Integer, String> map1 = new HashMap<>();
map1.put(1, "x");
map1.put(2, "y");
map1.put(3, "z");
map1.put(4, "a");
map1.put(5, "b");`
and
//2nd Map
Map<Integer, String> map2 = new HashMap<>();
map2.put(1, "fail");
map2.put(2, "fail");
map2.put(3, "fail");
map2.put(4, "pass");
map2.put(5, "pass");`
//the method
public Map<Integer, String>findFaildStudent(Map<Integer, String>map1,Map<Integer, String>map2){
returns Map<Integer, String>;
}
So, my question is how to find the record of failed students. I did try it myself but didn't succeed. Any help is appreciated.
What I tried so far
public Map<Integer, String>findFaildStudent(Map<Integer, String>map1,Map<Integer, String>map2){
Integer key = null;
String value = null;
Iterator<Entry<Integer, String>> iterator = map1.entrySet().iterator();
while(iterator.hasNext()){
Entry<Integer, String> next = iterator.next();
key = next.getKey();
}
Iterator<Entry<Integer, String>> iterator2 = map2.entrySet().iterator();
while(iterator2.hasNext()){
Entry<Integer, String> next = iterator2.next();
value=next.getValue();
}
Map<Integer,String> hashMap = new HashMap<>();
hashMap.put(key, value);
return hashMap;
}
public Map<String, String> findFaildStudent(Map<Integer, String>map1,Map<Integer, String>map2){
Map<String, String> failed = new HashMap<>();
for (Map.Entry<Integer, String> k : map2.entrySet()) {
if(k.getValue().equals("fail")){
failed.put(map1.get(k.getKey()), map2.get(k.getValue()));
}
}
return failed;
}
//returns... ("x","failed"), ("y", "failed"), ("z", "failed")
So basically you just need to iterate through the 2nd map since it contain failed student, then you get the key and use that key to get the value of map1.
You cannot concate the keys because the key is unique so if you want combine both map together it is better to create another map using map1(value) as key and map2(value) as value. Hope I understand your question but if you only want map2 of failed student then try below.
public Map<Integer, String> findFaildStudent(Map<Integer, String>map1,Map<Integer, String>map2){
Map<Integer, String> failed = new HashMap<>();
for (Map.Entry<Integer, String> k : map2.entrySet()) {
if(k.getValue().equals("fail")){
failed.put(k.getKey(), map1.get(k.getKey()));
}
}
return failed;
//returns... (1,"x"), (2, "y"), (3, "z")
map1.entrySet().stream()
.filter(entry -> "fail".equals(map2.get(entry.getKey())))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
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 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));
}