I am trying to check whether a map contains all contents of another map. For example, I have a mapA which is a Map<String, List<String>> and the elements are:
"1" -> ["a","b"]
"2" -> ["c","d"]
another mapB which is also a Map<String, List<String>>, the elements are:
"1" -> ["a"]
"2" -> ["c","d"],
I want to create a function compare(mapA, mapB) which will return false in this case.
What is the best way to do this?
Inside your compare(mapA, mapB) method, you can simply use:
return mapA.entrySet().containsAll(mapB.entrySet());
The answer provided by #Jacob G wont work in your case. It will work only if there is an extra (key, value) pair in MapA. like
MapA = {"1" -> ["a","b"] "2" -> ["c","d"] }
and
MapB = {"1" -> ["a","b"] }.
What you need is this:
boolean isStrictlyDominate(LinkedHashMap<Integer, HashSet<Integer>> firstMap, LinkedHashMap<Integer, HashSet<Integer>> secondMap){
for (Map.Entry<Integer, HashSet<Integer>> item : secondMap.entrySet()) {
int secondMapKey = item.getKey();
if(firstMap.containsKey(secondMapKey)) {
HashSet<Integer> secondMapValue = item.getValue();
HashSet<Integer> firstMapValue = firstMap.get(secondMapKey) ;
if(!firstMapValue.containsAll(secondMapValue)) {
return false;
}
}
}
return !firstMap.equals(secondMap);
}
(if you do not want to check strict domination then just return true at last return statement)
Try this code :
Assert.assertTrue(currentMap.entrySet().containsAll(expectedMap.entrySet()));
you can try this.
static boolean compare(Map<String, List<String>> mapA, Map<String, List<String>> mapB){
return mapA.entrySet().containsAll(mapB.entrySet());
}
As suppose, provided data is something like this:
Map<String, List<String>> mapA = new HashMap<>();
Map<String, List<String>> mapB = new HashMap<>();
mapA.put("1", Arrays.asList("a","b"));
mapA.put("2", Arrays.asList("c","d"));
mapB.put("1", Arrays.asList("a"));
mapB.put("2", Arrays.asList("c", "d"));
System.out.println(compare(mapA, mapB));
In this case compare(mapA, mapB) method will return false.
But suppose provided data is something like this:
Map<String, List<String>> mapA = new HashMap<>();
Map<String, List<String>> mapB = new HashMap<>();
mapA.put("1", Arrays.asList("a","b"));
mapA.put("2", Arrays.asList("c","d"));
mapB.put("1", Arrays.asList("a", "b"));
mapB.put("2", Arrays.asList("c", "d"));
System.out.println(compare(mapA, mapB));
In this case, compare(mapA, mapB) method, which I have written will return true.
compare(mapA, mapB) method basically checking for all the entries in mapA with mapB, if same returning yes, else returning false;
Related
I have a nested map as Map<String, Map<String, Boolean>> and would like to find if the inner map has at least one value as TRUE. I was able to do it using a loop but trying to do it using lambda expression
Using for loop:
Map<String, Map<String, Boolean>> maps = new HashMap<>();
Map<String, Boolean> test = new HashMap<>();
test.put("test1", Boolean.FALSE);
test.put("test2", Boolean.TRUE);
maps.put("hey", test);
Map<String, Boolean> testtt = new HashMap<>();
testtt.put("test3", Boolean.FALSE);
testtt.put("test4", Boolean.TRUE);
maps.put("lol", testtt);
Boolean val = Boolean.FALSE;
for(Map.Entry<String, Map<String, Boolean>> m: maps.entrySet()){
Map<String, Boolean> mm = m.getValue();
for(Map.Entry<String, Boolean> mmm: mm.entrySet()){
if(mmm.getValue()){
val = Boolean.TRUE;
break;
}
}
}
System.out.println(val);
I was able to do it using a loop but trying to do it using lambda expression.
Here is one way. Here the lambda will be based on a Predicate
first you need to stream the outer maps values (which is another map) and then stream the values of those.
Then it's a matter of using anyMatch() with an identity lambda to find the first true value.
Predicate<Map<String, Map<String, Boolean>>> hasTrue = m -> m.values()
.stream().flatMap(map -> map.values().stream()).anyMatch(a->a);
System.out.println(hasTrue.test(maps));
Prints
true
And a better way as suggested by Holger
maps.values().stream()
.anyMatch(innerMap -> innerMap.containsValue(true))
You can try changing the loop on something like this:
Map<String, Map<String, Boolean>> maps = new HashMap<>();
boolean hasValue = maps
.values()
.stream()
.flatMap(m -> m.values().stream())
.anyMatch(b -> b.getValue());
If I have a map with the following data:
"a", "hello"
"b", "bye"
"c", "good morning"
and a second map with the following data:
"key1","a"
"key2", "b"
"key3", "c"
is it then possible to perform an operation such that I can map the value of my second map onto the key as my first map? Which would result in the final map looking like this:
"key1","hello"
"key2", "bye"
"key3", "good morning"
Apparently you want a third map made of keys from the second map, and matching values from the first map.
Map< String , String > thirdMap = new HashMap<>() ;
for ( Map.Entry< String , String > entry : secondMap.entrySet() ) {
thirdMap.put(
entry.getKey() , // Second map’s key.
firstMap.get( entry.getValue() ) // First map’s value.
);
}
The below code should work, for what you are trying to do
public static void main(final String[] args) throws Exception {
HashMap<String, String> keyToValue = new HashMap<String, String>() {{
put("a", "hello");
put("b", "bye");
put("c", "good morning");
}};
HashMap<String, String> keyToSecondaryKey = new HashMap<String, String>() {{
put("key1", "a");
put("key2", "b");
put("key3", "c");
}};
keyToSecondaryKey.entrySet().forEach(e-> {
e.setValue(keyToValue.get(e.getValue()));
});
System.out.println(keyToSecondaryKey);
}
In this way:
Map<String, String> map1 = new HashMap<>();
map1.put("a", "hello");
map1.put("b", "bye");
map1.put("c", "good morning");
Map<String, String> map2 = new HashMap<>();
map2.put("key1", "a");
map2.put("key2", "b");
map2.put("key3", "c");
map2.forEach((key2, value2) -> map2.put(key2, map1.get(value2)));
This may work for you. Note that this creates a third map.
Map<String, String> map1 =
Map.of("a", "hello", "b", "bye", "c", "good morning");
Map<String, String> map2 =
Map.of("key1", "a", "key2", "b", "key3", "c");
Stream the entry set of map2
Use that entry's key as the key to the result map
use that entry's value as the key to retrieve the value of map1
Map<String, String> result = map2.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey,
e->map1.get(e.getValue())));
result.entrySet().forEach(System.out::println);
prints
key1=hello
key2=bye
key3=good morning
As I've mentioned in the comment the statement below will print "hello". And there's no need to do create a third map if you want to access the content of these two maps right in the same code.
System.out.println(fistMap.get(secondMap.get("key1")));
With the following code, you can iterate print the keys of the second map and the values of the first map (with the assumption that all values of the second map are present in the first map as keys).
fistMap.forEach((k, v) -> System.out.println(k + " -> " + secondMap.get(v)));
And only if you need to pass the data from these two maps to another part of your application it might make sense to create the third combined map. It could be done with the Stream IPA like that:
Map<String, String> combinedMap =
secondMap.keySet().stream()
.collect(Collectors.toMap(Function.identity(), // key of the new map
k -> fistMap.get(secondMap.get(k)))); // value of the new map
The method takes in two parameters - a Map and a Set. Converts the Set to a List and starts looking for a match-a List item with a key in the Map.If a match occurs, it copies an element of the old Map to the new Map.
public Map<String, Boolean> getValidMap(Set<String> set, Map<String, Boolean> map) {
Map<String, Boolean> validMap = new HashMap<>();
List<String> mainList = new ArrayList<>(set);
for (String listRule : mainList) {
for (Map.Entry<String, Boolean> mapRule : map.entrySet()) {
if (listRule.equals(mapRule.getKey()))
validMap.put(mapRule.getKey(), mapRule.getValue());
}
}
return validMap;
}
I would like to replace the loops FOR and the IF condition with lambda expressions and streams.I am not familiar with streams and lambdas so I ask for help with this question.
Basically, you can stream the Map and then filter entries having the key in input set and finally collect those entries into Map and return it
return map.entrySet().stream()
.filter(entry->set.contains(entry.getKey())
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));
You can just use a for directly from the Set and use computeIfPresent:
public static Map<String, Boolean> getValidMap2(Set<String> set, Map<String,
Boolean> map) {
Map<String, Boolean> validMap = new HashMap<>();
set.forEach(s -> map.computeIfPresent(s, validMap::put));
return validMap;
}
How to get key from any values in the list for below hashmap?
Map<String, List<String>> map = new HashMap<String, List<String>>();
"car" : ["toyota", "bmw", "honda"]
"fruit" : ["apple","banana"]
"computer" : ["acer","asus","ibm"]
if I pass the value as "ibm", I need to get key as "computer", for "bmw" input need to get key as "car".
I am using below code to get key, need any short or better options
map.forEach((k, v) -> {
List<String> list = v;
}
Key from List
for each entry in map check if values contains you keyword
String value = "ibm";
Optional<String> key = map.entrySet().stream()
.filter(e -> e.getValue().contains(value))
.map(Entry::getKey)
.findFirst();
System.out.println(key.get());
If you'd like to be fancy, you could use Guava's BiMap.
Here's an example taken from baeldung:
#Test
public void givenBiMap_whenQueryByValue_shouldReturnKey() {
BiMap<String, String> capitalCountryBiMap = HashBiMap.create();
capitalCountryBiMap.put("New Delhi", "India");
capitalCountryBiMap.put("Washington, D.C.", "USA");
capitalCountryBiMap.put("Moscow", "Russia");
String keyFromBiMap = capitalCountryBiMap.inverse().get("Russia");
String valueFromBiMap = capitalCountryBiMap.get("Washington, D.C.");
assertEquals("Moscow", keyFromBiMap);
assertEquals("USA", valueFromBiMap);
}
I want to be able to convert a List to a HashMap where the key is the elementName and the values is a list of something random (in this case its the Element Name). So in short I want (A->List(A), B->List(B), C-> List(C)). I tried using toMap() and passing it the keyMapper and ValueMapper but I get a compilation error. I would really appreciate if someone can help me out.
Thanks!
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> list = Arrays.asList("A","B","C","D");
Map<String, List<String>> map = list.stream().map((element)->{
Map<String, List<String>> map = new HashMap<>();
map.put(element, Arrays.asList(element));
return map;
}).collect(??);
}
Function<Map<String, String>, String> key = (map) -> {
return map.keySet().stream().findFirst().get();
};
Function<Map<String, String>, String> value = (map) -> {
return map.values().stream().findFirst().get();
};
=== This worked for me
Thanks for all the help guys! #izstas "they should operate on the elements" helped a lot :). Actually this is what I was looking for to be exact
public static void test2 (){
Function<Entry<String, List<String>>, String> key = (entry) -> {
return entry.getKey();
};
Function<Entry<String, List<String>>, List<String>> value = (entry) -> {
return new ArrayList<String>(entry.getValue());
};
BinaryOperator<List<String>> merge = (old, latest)->{
old.addAll(latest);
return old;
};
Map<String, List<String>> map1 = new HashMap<>();
map1.put("A", Arrays.asList("A1", "A2"));
map1.put("B", Arrays.asList("B1"));
map1.put("D", Arrays.asList("D1"));
Map<String, List<String>> map2 = new HashMap<>();
map2.put("C", Arrays.asList("C1","C2"));
map2.put("D", Arrays.asList("D2"));
Stream<Map<String, List<String>>> stream =Stream.of(map1, map2);
System.out.println(stream.flatMap((map)->{
return map.entrySet().stream();
}).collect(Collectors.toMap(key, value, merge)));
}
You can use the groupingBy method to manage aggregation, for example:
public static void main(String[] args) {
List<String> list = Arrays.asList("A", "B", "C", "D", "A");
Map<String, List<String>> map = list.stream().collect(Collectors.groupingBy(Function.identity()));
}
If you want more flexibility (for example to map the value and return a Set instead of a List) you can always use the groupingBy method with more parameters as specified in javadoc:
Map<City, Set<String>> namesByCity = people.stream().collect(Collectors.groupingBy(Person::getCity, mapping(Person::getLastName, toSet())));
Functions key and value you have defined in your code are not correct because they should operate on the elements of your list, and your elements are not Maps.
The following code works for me:
List<String> list = Arrays.asList("A", "B", "C", "D");
Map<String, List<String>> map = list.stream()
.collect(Collectors.toMap(Function.identity(), Arrays::asList));
First argument to Collectors.toMap defines how to make a key from the list element (leaving it as is), second argument defines how to make a value (making an ArrayList with a single element).
Thanks for all the help guys! #izstas "they should operate on the elements" helped a lot :). Actually this is what I was looking for to be exact
public static void test2 (){
Function<Entry<String, List<String>>, String> key = (entry) -> {
return entry.getKey();
};
Function<Entry<String, List<String>>, List<String>> value = (entry) -> {
return new ArrayList<String>(entry.getValue());
};
BinaryOperator<List<String>> merge = (old, latest)->{
old.addAll(latest);
return old;
};
Map<String, List<String>> map1 = new HashMap<>();
map1.put("A", Arrays.asList("A1", "A2"));
map1.put("B", Arrays.asList("B1"));
map1.put("D", Arrays.asList("D1"));
Map<String, List<String>> map2 = new HashMap<>();
map2.put("C", Arrays.asList("C1","C2"));
map2.put("D", Arrays.asList("D2"));
Stream<Map<String, List<String>>> stream =Stream.of(map1, map2);
System.out.println(stream.flatMap((map)->{
return map.entrySet().stream();
}).collect(Collectors.toMap(key, value, merge)));
}