I have produced two multimaps in Java like this:
TreeMap1 = {key1=[a,b,c], key2=[d,e,f]}
TreeMap2 = {key1=[j,k], key2=[z,p]}
How can I add the values of TreeMap2, with similar key as in TreeMap1, to the values of TreeMap1, and produce a third TreeMap Like:
TreeMap3 = {key1=[a,b,c,j,k], key2=[d,e,f,z,p]}
This Method gives me nothing.
public TreeMap<String, List<String>> make_TreeMap3(){
for(Entry<String,List<String>> entry_t1 :this.map_FuncType.entrySet()){
for(Entry<String,List<String>> entry_t2 : this.map_AufOrgUserField.entrySet()){
if(entry_t2.getKey().contains(entry_t1.getKey())){
entry_t2.getValue().addAll(entry_t1.getValue());
}
}
}
return map_mergOrgandType;
}
Something like this?
TreeMap<String, List<String>> treeMap3 = new TreeMap<>(treeMap1);
for (String k : treeMap3.keySet()) {
if (treeMap2.containsKey(k)) {
treeMap3.get(k).addAll(treeMap2.get(k));
}
}
return treeMap3;
It's very easy to do in Guava if you're open to using a 3rd party library.
public class MultimapMerge {
public static void main(String[] args) {
Multimap<String, String> map1 = TreeMultimap.create();
map1.put("key1", "a");
map1.put("key1", "b");
map1.put("key1", "c");
map1.put("key2", "d");
map1.put("key2", "e");
map1.put("key2", "f");
Multimap<String, String> map2 = TreeMultimap.create();
map2.put("key1", "j");
map2.put("key1", "k");
map2.put("key2", "z");
map2.put("key2", "p");
Multimap<String, String> map3 = TreeMultimap.create();
map3.putAll(map1);
map3.putAll(map2);
System.out.println(map3);
}
}
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Multimap.html
Related
I have a hashmap with some keys pointing to same values. I want to find all the values that are equal and print the corresponding keys.
This is the current code that I have:
Map<String, String> map = new HashMap<>();
map.put("hello", "0123");
map.put("hola", "0123");
map.put("kosta", "0123");
map.put("da", "03");
map.put("notda", "013");
map.put("twins2", "01");
map.put("twins22", "01");
List<String> myList = new ArrayList<>();
for (Map.Entry<String, String> entry : map.entrySet()) {
for (Map.Entry<String, String> entry2 : map.entrySet()){
if (entry.getValue().equals(entry2.getValue()))
{
myList.add(entry.getKey());
}
}
}
The current code adds the duplicates two times into the list, however it also adds every key one time.
Thanks.
You can use streams to retrive duplicates in this way:
List<String> myList = map.stream()
.filter(n -> Collections.frequency(map.values(), n) > 1)
.collect(Collectors.toList());
And then, you can print this out with:
myList.foreach(System.out::println);
Build a Map<VALUE, List<KEY>>, i.e. a Map<String, List<String>>.
Example
Map<String, String> map = new HashMap<>();
map.put("hello", "0123");
map.put("hola", "0123");
map.put("kosta", "0123");
map.put("da", "03");
map.put("notda", "013");
map.put("twins2", "01");
map.put("twins22", "01");
map.entrySet().stream()
.collect(Collectors.groupingBy(Entry::getValue,
Collectors.mapping(Entry::getKey, Collectors.toList())))
.entrySet().stream()
.filter(e -> e.getValue().size() > 1)
.forEach(System.out::println);
Output
01=[twins22, twins2]
0123=[kosta, hello, hola]
Without the filter(), the result would be:
01=[twins22, twins2]
013=[notda]
03=[da]
0123=[kosta, hello, hola]
If you want a solution beside to Stream API;
public static void duplicatedValuesMap() {
Map<String, String> map = new HashMap<>();
map.put("hello", "0123");
map.put("hola", "0123");
map.put("kosta", "0123 test");
map.put("da", "03");
map.put("notda", "013");
map.put("twins2", "01");
map.put("twins22", "01");
HashMap<String, List<String>> valueToKeyMapCounter = new HashMap<>();
for (Map.Entry<String, String> entry : map.entrySet()) {
if (valueToKeyMapCounter.containsKey(entry.getValue())) {
valueToKeyMapCounter.get(entry.getValue()).add(entry.getKey());
} else {
List<String> keys = new ArrayList<>();
keys.add(entry.getKey());
valueToKeyMapCounter.put(entry.getValue(), keys);
}
}
for (Map.Entry<String, List<String>> counterEntry : valueToKeyMapCounter.entrySet()) {
if (counterEntry.getValue().size() > 1) {
System.out.println("Duplicated Value:" + counterEntry.getKey() + " for Keys:" + counterEntry.getValue());
}
}
}
I think other answers already good to solve the question, i support another method to do just for extended thinking.This method need use Guava's MutliMap interface:
// init the input map
Map<String, String> map = new HashMap<>();
map.put("hello", "0123");
map.put("hola", "0123");
map.put("kosta", "0123");
map.put("da", "03");
map.put("notda", "013");
map.put("twins2", "01");
map.put("twins22", "01");
// swap key and value of the input map,since different key has same value
// so we need Multimap
Multimap<String, String> container = ArrayListMultimap.create();
map.entrySet().forEach(entry -> container.put(entry.getValue(), entry.getKey()));
container.keySet().stream()
.filter(s -> container.get(s).size() > 1).
forEach(System.out::println);
output:
01
0123
ArrayList<Map<String, String>> result1
result1 is like
(1, a)
(2, a)
(3, b)
(4, e)
(5, e)
ArrayList<Map<String, String>> result2
result2 is like
(1,android)
(2,ios)
(3,android)
(4,android)
(5,ios)
I want to merge the two maps to build a map like this one
(1, ( a, android))
(2, ( a, ios))
(3, ( b, android))
(4, (e, android))
(5, (e, ios))
How to make this happen?
You can merge two streams with Stream.concat() and group them with Collectors.groupingBy() and Collectors.mapping():
Map<String, String> first = Map.of("1", "a", "2", "a");
Map<String, String> second = Map.of("1", "android", "2", "ios");
Map<String, List<String>> result = Stream.concat(first.entrySet().stream(), second.entrySet().stream())
.collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList())));
System.out.println(result);
will output:
{1=[a, android], 2=[a, ios]}
For the requirement you have specified here, you can do it like this.
I'm iterating over the keys of the first map. And collecting values for each key from all the maps and putting them in a list. Then put the list to the resulting map.
import java.util.*;
public class MergeMaps
{
public static void main(String[] args)
{
Map<String, String> map1 = new HashMap<>();
map1.put("1", "a");
map1.put("2", "a");
map1.put("3", "b");
map1.put("4", "e");
map1.put("5", "e");
Map<String, String> map2 = new HashMap<>();
map2.put("1", "android");
map2.put("2", "ios");
map2.put("3", "android");
map2.put("4", "android");
map2.put("5", "ios");
Set<String> keys = new HashSet<>();
keys.addAll(map1.keySet());
keys.addAll(map2.keySet());
Map<String, List<String>> mergedMap = new HashMap<>();
for (String key : keys)
{
List<String> list = new ArrayList<>();
list.add(map1.get(key));
list.add(map2.get(key));
mergedMap.put(key, list);
}
System.out.println(mergedMap);
}
}
Output will be:
{1=[a, android], 2=[a, ios], 3=[b, android], 4=[e, android], 5=[e, ios]}
You can try this approach as well:
Map<String, String> result1 = new HashMap<>();
// initialize result1 ...
Map<String, String> result2 = new HashMap<>();
// initialize result2 ...
Map<String, Map<String, String>> mergedResult = new HashMap<>();
Up to Java 8
result1.forEach((k1, v1) ->
mergedResult.put(k1, new HashMap<String, String>() {{
put(v1, result2.get(k1));
}}));
Java 9 or later
result1.forEach((k1, v1) -> mergedResult.put(k1,
Map.of(v1, result2.get(k1))));
This is one way arriving at the result:
Input Data:
// The first list of data
List<Map<String, String>> list1 = new ArrayList<>();
list1.add(getMapData("1", "a"));
list1.add(getMapData("2", "a"));
list1.add(getMapData("3", "b"));
list1.add(getMapData("4", "e"));
list1.add(getMapData("5", "e"));
list1.add(getMapData("999", "x"));
System.out.println(list1);
Data 1: [{1=a}, {2=a}, {3=b}, {4=e}, {5=e}, {999=x}]
// The second list of data
List<Map<String, String>> list2 = new ArrayList<>();
list2.add(getMapData("1", "android"));
list2.add(getMapData("2", "ios"));
list2.add(getMapData("3", "android"));
list2.add(getMapData("4", "android"));
list2.add(getMapData("5", "ios"));
list2.add(getMapData("888", "zzzzz"));
System.out.println(list2);
Data 2: [{1=android}, {2=ios}, {3=android}, {4=android}, {5=ios}, {888=zzzzz}]
// utility method for creating test data
private static Map<String, String> getMapData(String k, String v) {
Map<String, String> m = new HashMap<>();
m.put(k, v);
return m;
}
The Result Process:
The output is stored to a Map<String, List<String>>:
Map<String, List<String>> result = new HashMap<>();
// process the first list
for (Map<String, String> m : list1) {
for (Map.Entry<String, String> entry : m.entrySet()) {
List<String> valueList = new ArrayList<>();
valueList.add(entry.getValue());
result.put(entry.getKey(), valueList);
}
}
// process the second list; merge with the first
for (Map<String, String> m : list2) {
for (Map.Entry<String, String> entry : m.entrySet()) {
String k = entry.getKey();
List<String> valueList = result.get(k);
if (valueList == null) {
valueList = new ArrayList<>();
}
valueList.add(entry.getValue());
result.put(k, valueList);
}
}
System.out.println(result);
The Result:
{1=[a, android], 2=[a, ios], 3=[b, android], 4=[e, android], 5=[e, ios], 888=[zzzzz], 999=[x]}
There are 2 LinkedHashMaps. I have to check if both LinkedHashMaps have same keys & values. If one LinkedHashMap contains extra keys + values then it should get printed or stored in 3rd LinkedHashMap. If any of the key or value is different in 2nd LinkedHashMap then it should be notified (print in console)
Eg
Map1 contains {A-a, B-b, C-c}
Map2 contains {A-a, B-r, C-c, Z-z}
So here 3rd LinkedHashMap should contain {Z-z} as it contains extra key and
{B-r} should get printed as it is modified
you can use this class :)
public class MapCompare {
private LinkedHashMap<String, String> differencesMap;
private LinkedHashMap<String, String> extraMap;
private void main(LinkedHashMap<String, String> map1, LinkedHashMap<String, String> map2) {
this.differencesMap = new LinkedHashMap<>();
this.extraMap = new LinkedHashMap<>();
Set<Map.Entry<String, String>> set1 = ((LinkedHashMap<String, String>) map1.clone()).entrySet();
Set<Map.Entry<String, String>> set2 = ((LinkedHashMap<String, String>) map2.clone()).entrySet();
set1.removeAll(set2);
compare(set1, map2);
set1 = map1.entrySet();
set2.removeAll(set1);
compare(set2, map1);
}
private LinkedHashMap<String, String> getDifferencesMap() {
return differencesMap;
}
private LinkedHashMap<String, String> getExtraMap() {
return extraMap;
}
private void compare(Set<Map.Entry<String, String>> set, LinkedHashMap<String, String> map) {
for (Map.Entry<String, String> entry : set) {
String key = entry.getKey();
String value = entry.getValue();
if (map.containsKey(key) || map.containsValue(value)) {
differencesMap.put(key, value);
} else {
extraMap.put(key, value);
}
}
}
public static void main(String[] args) {
LinkedHashMap<String, String> map1 = new LinkedHashMap<>();
map1.put("A", "a");
map1.put("B", "b");
map1.put("C", "c");
LinkedHashMap<String, String> map2 = new LinkedHashMap<>();
map2.put("A", "a");
map2.put("C", "c");
map2.put("B", "r");
map2.put("Z", "z");
MapCompare mapCompare = new MapCompare();
mapCompare.main(map1,map2);
System.out.println("diff: " + mapCompare.getDifferencesMap());
System.out.println("extra: " + mapCompare.getExtraMap());
}
}
I have a requirement where I have to filter object from list based on multiple dynamic filter condition.
I have already written code by looping over objects and then all filter and returning false if any condition doesn't match. The code that I have written is as
Map<String, String> obj1 = new HashMap<>();
obj1.put("id", "1");
obj1.put("name", "name1");
obj1.put("dept", "IT");
obj1.put("sex", "M");
Map<String, String> obj2 = new HashMap<>();
obj2.put("id", "2");
obj2.put("name", "name2");
obj2.put("dept", "IT");
obj2.put("sex", "M");
Map<String, String> obj3 = new HashMap<>();
obj3.put("id", "3");
obj3.put("name", "name3");
obj3.put("dept", "DEV");
obj3.put("sex", "F");
ArrayList<Map<String, String>> employees = new ArrayList<>(Arrays.asList(obj1,obj2,obj3));
Map<String, String> filterCondition = new HashMap<>();
filterCondition.put("dept", "IT");
filterCondition.put("sex", "M");
List<Map<String, String>> filteredEmployee = new ArrayList<>();
for(Map<String,String> employee:employees){
if(isValid(filterCondition, employee)){
filteredEmployee.add(employee);
}
}
System.out.println(filteredEmployee);
isValid method is as
private static boolean isValid(Map<String, String> filterCondition, Map<String, String> employee) {
for(Entry<String, String> filterEntry:filterCondition.entrySet()){
if(!employee.get(filterEntry.getKey()).equals(filterEntry.getValue())){
return false;
}
}
return true;
}
Is there any better way to achieve it if filters that I am getting is coming dynamically.
I have already seen some answer in stackoverflow as here ,but with no help
Combine all filters as a single Predicate (using stream, reduce, and predicate composition):
Predicate<Map<String, String>> allConditions = filterCondition
.entrySet()
.stream()
.map(ThisClass::getAsPredicate)
.reduce((employee) -> true, Predicate::and);
Then just use Stream.filter()
List<Map<String, String>> filteredEmployees = employees
.stream()
.filter(allConditions)
.collect(Collectors.toList());
Helper function:
private static Predicate<Map<String, String>> getAsPredicate(Map.Entry<String, String> filter) {
return (Map<String, String> employee) -> employee.get(filter.getKey()).equals(filter.getValue());
}
Maybe you can use for-loop with Stream:
Stream<Map<String, String>> employeeStream = employees.stream();
for (Map.Entry<String, String> entry : filterCondition.entrySet()) {
employeeStream = employeeStream.filter(map -> entry.getValue()
.equals(map.get(entry.getKey())));
}
List<Map<String, String>> filteredEmployee = employeeStream.collect(Collectors.toList());
can map be compare with arraylist of string in java
private Map<String, String> checkInScopeLobs(Map<String, String> allLobsChkBx)
{
Map<String, String> inScopeLobs = new HashMap<String, String>();;
for (Map.Entry<String, String> entry : allLobsChkBx.entrySet())
{
if(entry.getKey().contains("1") || entry.getKey().contains("2") || entry.getKey().contains("3")){
inScopeLobs.put(entry.getKey(), entry.getValue());
}
}
return inScopeLobs;
}
is this a correct way ?
You can make use of keySet(). This method returns a Set of keys (for more info, Docs from Oracle about Map). This means less overhead than iterating over your whole map. In the following case you'll only request values of matching keys.
There are some other faults like a double semicolon and since JDK7 you don't have to define your map when initializing.
private Map<String, String> checkInScopeLobs(Map<String, String> allLobsChkBx) {
Map<String, String> inScopeLobs = new HashMap();
List<String> keys = Arrays.asList( { "1", "2", "3" } );
for(String key : allLobsChkBx.keySet()) {
if(keys.contains(key)) {
inScopeLobs.put(key, allLobsChkBx.get(key));
}
}
return inScopeLobs;
}
Why aren't you using an Integer instead of a String, since you're only storing numbers.
Since key is String you can use matches method from String class
for (Map.Entry<String, String> entry : allLobsChkBx.entrySet())
{
if(entry.getKey().matches(".*[123].*")){
inScopeLobs.put(entry.getKey(), entry.getValue());
}
}
Actually there are no such methods, but you can try this approach:
Map<String, String> allLobsChkBx = new HashMap<String, String>(4);
allLobsChkBx.put("1", "A");
allLobsChkBx.put("2", "B");
allLobsChkBx.put("3", "C");
allLobsChkBx.put("4", "D");
allLobsChkBx.put("5", "E");
System.out.println("Before retain: " + allLobsChkBx);
List<String> keysToRetain = Arrays.asList(new String[] { "1", "2", "3" });
allLobsChkBx.keySet().retainAll(keysToRetain);
System.out.println("After retain: " + allLobsChkBx);
It will produce following output:
Before retain: {3=C, 2=B, 1=A, 5=E, 4=D}
After retain: {3=C, 2=B, 1=A}