Get key from any values in list - java

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);
}

Related

Inititialize Map keys from list with a default value

I need to initialize the keys of a map from a list and give a default value for each entry.
Currently I use a for loop :
Map<String, String > myMap = new HashMap<>();
List<String> keys = Arrays.asList("a", "b", "c", "d");
for (String key : keys){
myMap.put(key, "default");
}
Is there a cleaner way to do that ? Stream or lambda maybe ?
Yes, you can create a Stream of that List's elements and collect them to a Map:
Map<String,String> map = keys.stream ()
.collect (Collectors.toMap (Function.identity (),
k -> "default"));

Java 8 : how to extract a HashMap from a ArrayList of HashMap in Java 8 using streams?

I have the following sample result when I query a database :
dataList = [{ name : name1, rollno: rollno1 }, { name : name2, rollno: rollno2 } ]
I want to convert this list of hashmaps into a single hashmap using Java 8 streams.
I tried using Collectors.toMap() but i am not sure how to refer to rollNo as key and the hashmap as the value inside the toMap method.
Exected output :
{ rollno1 : { name : name1, rollno: rollno1 } , rollno2 : { name : name2, rollno: rollno2 } }
I tried doing it using a for each loop on the list and then adding the rollno as key to a hashmap and the hashmap as value itself of that rollno.
HashMap<String,HashMap<String,String>> newMap = new HashMap();
for(HashMap<String,String> record : dataList){
String key = record.get("rollno").toString();
newMap.put(key,record);
}
Is there a way to refactor this code using functional streams in Java 8?
Will using streams collect method give any performance advantage over the foreach for doing this?
Will appreciate any leads. Thanks
Here's complete example how to do it
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<HashMap<String, String>> input = new ArrayList<>();
HashMap<String, String> subinput1 = new HashMap<>();
subinput1.put("name", "name1");
subinput1.put("rollno", "rollno1");
input.add(subinput1);
HashMap<String, String> subinput2 = new HashMap<>();
subinput2.put("name", "name2");
subinput2.put("rollno", "rollno2");
input.add(subinput2);
HashMap<String, HashMap<String, String>> result = (HashMap<String, HashMap<String, String>>) input.stream()
.collect(Collectors.toMap(v -> (String) v.get("rollno"), e -> e));
System.out.println(result);
}
}
It iterates over a collection of HashMaps, takes the key in which it should be stored in the result HashMap, then it creates a Map of Maps where the key is the "rollno" from the input map, and value is the input map itself.
As I don't know the type of Object you are using, so I am performing this on String. But it is valid for any type of object.
HashMap result = (HashMap<String, HashMap<String, String>>) listOfHashMaps.stream()
.collect(Collectors.toMap(e-> e.get("roll"),e->e));
As type casting will help you to achieve this.
You can use Collectors.toMap with Function.identity() as below,
list.stream()
.collect(toMap(e->e.get("rollno"), Function.identity()));
public static void main(String[] args) {
List<HashMap<String, String>> input = new ArrayList<>();
HashMap<String, String> subinput1 = new HashMap<>();
subinput1.put("name", "name1");
subinput1.put("rollno", "rollno1");
input.add(subinput1);
HashMap<String, String> subinput2 = new HashMap<>();
subinput2.put("name", "name2");
subinput2.put("rollno", "rollno2");
input.add(subinput2);
//Test key conflict
HashMap<String, String> subinput3 = new HashMap<>();
subinput2.put("name", "name3");
subinput2.put("rollno", "rollno2");
input.add(subinput2);
System.out.println("input:"+ JSONObject.toJSONString(input));
HashMap<String, HashMap<String, String>> result = (HashMap<String, HashMap<String, String>>)
input.stream()
.collect(Collectors.toMap(
v -> (String) v.get("rollno"),
Function.identity(),(oldValue, newValue) -> newValue
));
//fastjson hashmap-toString use =
System.out.println(JSONObject.toJSONString(result));
}
Probably something like this:
Map<RollNo, List<Roll>> rollsPerType = rolls.stream()
.collect(groupingBy(Roll::getRollNo));
where Roll is the main object and RollNo is the property inside (since you didn't provide the actual definitions).

Check whether a map contains all contents of another map

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;

How do I reverse a map with a Set<Integer> included?

For instance if I have a map with integer and strings:
Map<Integer, String> myMap = new HashMap<Integer, String>();
This map would contain key values of Integers and values of names.
What I am trying to do is make a new map, that copies all the values (names) from theMap and makes them the keys for the new map. Now the tricky part I can't get, is that I want the values of the new map to be the numbers, but if there are multiple numbers that correspond to the same name I want them to be held in an Set.
Example of new map:
Map<String, Set<Integer>> returnMap = new TreeMap<String, Set<Integer>>();
So if "John" corresponds to 1,2,3,4. I would like the new map to contain a key of "John" with a Set containing 1,2,3,4
Google's Guava library has a nice Multimap class which maps keys to multiple values. If you use it, you can take advantage of a host of helper methods:
SetMultimap<String, Integer> returnMap =
Multimaps.invertFrom(Multimaps.forMap(myMap), TreeMultimap.create());
It's not that tricky :)
Map<Integer, String> map = ... //Your map
Map<String, Set<Integer>> reverseMap = new TreeMap<String, Set<Integer>>();
for(Map.Entry<Integer, String> entry : map.entrySet()) {
Integer key = entry.getKey();
String value = entry.getValue();
Set<Integer> set;
if(reverseMap.containsKey(value)) {
set = reverseMap.get(value);
set.add(key);
} else {
set = new HashSet<Integer>();
set.add(key);
reverseMap.put(value, set);
}
}

Identify the Key-Value pair having duplicate values

I have a multimap like below:
{20014=[13123], 20013=[45451, 13123]}
where the keys and values are in String
If there is any duplicate in the value from other key, I have to print that key-value pair. In this case, it will be Key-20013,Value-13123.
How to achieve this?
I checked this link but not getting how to get the duplicate pair.
It could be done like this:
// Initialize my multimap
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("20014", "13123");
multimap.put("20013", "45451");
multimap.put("20013", "13123");
// Set in which we store the values to know if they exist already
Set<String> allValues = new HashSet<>();
// Convert the multimap into a Map
Map<String, Collection<String>> map = multimap.asMap();
// Iterate over the existing entries
for (Map.Entry<String, Collection<String>> entry : map.entrySet()) {
String key = entry.getKey();
Collection<String> values = entry.getValue();
// Iterate over the existing values for a given key
for (String value : values) {
// Check if the value has already been defined if so print a log message
if (!allValues.add(value)) {
System.out.println(String.format("Key-%s,Value-%s", key, value));
}
}
}
Output:
Key-20013,Value-13123
You can invert your multimap and, viewed as a map, iterate through its entries:
Multimap<String, String> inverse = Multimaps.invertFrom(multimap, HashMultimap.create());
for (Map.Entry<String, Collection<String>> entry : inverse.asMap().entrySet()) {
String value = entry.getKey();
Iterator<String> keysIterator = entry.getValue().iterator();
assert keysIterator.hasNext() : "there is always at least one key";
keysIterator.next(); // skip first key
while (keysIterator.hasNext()) { // each additional key is a duplicate
String key = keysIterator.next();
System.out.println(String.format("Key-%s,Value-%s", key, value));
}
}
Output:
Key-20013,Value-13123
If you are using an ImmutableMultimap then instead of Multimaps.invertFrom(Multimap, M) you can simply use ImmutableMultimap.inverse():
ImmutableMultimap<String, String> inverse = multimap.inverse();
If you simply want a map of duplicated values to their respective keys then you can use Maps.filterValues(Map, Predicate):
Map<String, Collection<String>> keysByDuplicatedValue = Maps.filterValues(inverse.asMap(),
keys -> keys.size() > 1);
Which will give you a map like below:
{13123=[20014, 20013]}

Categories

Resources