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"));
Related
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
I'm trying to remove a particular key from Map and reposition all keys index wise. For example: My map is like Map<Integer,String>
0,"A"
1,"B"
2,"C"
3,"D"
if i remove key 1 then output should be
0,"A"
1,"C"
2,"D"
How do i keep keys in index wise (0 to size-1) and assign next value to previous key after remove?
This is required because before insertion in map i need to check whether key exists or not. This scenario required for my recycler view adapter to hold unique positions to avoid reloading of items if exists in map
In your situation, if u want the index to be in that behavior. Map is not the answer. use List - can use ArrayList[insertion is often] or LinkedList[fast when reading].
Sample:
List<String> items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
items.add("D");
So if you remove index 1 or B;
items.remove(1);
The index of C will automatically be 1. Just like you wanted above.
Maps inherently have no order. There is no way to change the keys without taking all the values out of the Map and reinserting them with new keys.
It sounds like you may be better off using a List instead of a Map.
ArrayList<String> strings = new ArrayList(Arrays.asList("A", "B", "C"));
// 0 => "A", 1 => "B", 2 => "C"
strings.remove(1);
// 0 => "A", 1 => "C"
You can't order the keys on deletion by updating key values. In MAP only way to update keys is removing the key and and re-insert it with new value. That is tricky and expensive. You can go with ArrayList for the desired result as suggested.
The TreeMap<K,V> in the jdk java.util package can meet your needs. Whatever key you delete , the sort will never change.
If you want to define yourself sort method, just use its custom comparator to over-write construction method TreeMap(Comparator<? super K> comparator) to achieve key sorting.
public static void main(String[] args) {
Map<Integer, String> map = new TreeMap<Integer, String>();
map.put(0, "A");
map.put(1, "B");
map.put(2, "C");
map.put(3, "D");
// whatever key you delete , the sort will not change...
for (Map.Entry<Integer, String> entry : resultMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
you choose a very bad way to implement this in adapter
but you can solve it with below code:
final Map<Integer, String> myStupidMap = new HashMap<>();
myStupidMap.put(1, "A");
myStupidMap.put(2, "B");
myStupidMap.put(3, "C");
myStupidMap.put(4, "D");
final int[] count = {0};
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
myStupidMap.forEach(new BiConsumer<Integer, String>() {
#Override
public void accept(Integer integer, String s) {
if (count[0] == 1){
myStupidMap.remove(integer);
}
count[0]++;
}
});
}
i hope useful for you But my suggestion is not to use the map.
I am trying to create a Set and Collection from a HashMap that is within another HashMap. The problem is that the getKey() method is not applicable.
HashMap<HashMap<String, String>, String> list = getList(issues);
Set <String> set1 = list.getKey().keySet();
Collection <String> set2 = list.getKey().values();
From your collection, to get all the keys of each entry, you have to loop over each entry and get the keys, to do that using Java-8+, you can use:
Set<String> allKeys = list.entrySet().stream()
.flatMap(e -> e.getKey().keySet().stream())
.collect(Collectors.toSet());
To get the value, you can do it like this:
List<String> allValues = list.entrySet().stream()
.flatMap(e -> e.getKey().values().stream())
.collect(Collectors.toList());
Get Keys
//Get Keys of childHashMap
Set<String> keys = parent.keySet().stream().
flatMap(child -> child.keySet().stream()).
collect(Collectors.toSet());
1.Stream on keySet of parent hashMap (Iterate on child hashmap)
parent.keySet().stream()
2.Return keySet of child hashmap (it's like {1},{2,3},{4,5})
child -> child.keySet().stream()
3.Flat the previous step Set (it's like convert {1},{2,3},{4,5} to {1,2,3,4,5})
flatMap(child -> child.keySet().stream()).
4.Return keys
collect(Collectors.toSet());
Get Values
//Get Values of childHashMap
Collection<String> values = parent.keySet().stream()
.map(HashMap::values)
.flatMap(Collection::stream)
.collect(Collectors.toList());
1.Stream keySet of parent hashMap (Iterate on child hashmap)
parent.keySet().stream()
2.Return values of the child hashMap (its like : {1},{2},{3})
map(HashMap::values)
3.Use of flatMap to flat the previous step (Convert {1},{2},{3} to {1,2,3})
flatMap(Collection::stream)
4.Collect values to a List
collect(Collectors.toList())
Sample
//Parent
HashMap<HashMap<String, String>, String> parent = new HashMap<>();
//Child HashMap 1
HashMap<String, String> childHashMap = new HashMap<>();
childHashMap.put("a", "b");
//Child HashMap2
HashMap<String, String> childHashMap2 = new HashMap<>();
childHashMap2.put("d", "e");
//Parent init
parent.put(childHashMap, "c");
parent.put(childHashMap2, "f");
//Get Keys
Set<String> keys = parent.keySet().stream().flatMap(child -> child.keySet().stream()).collect(Collectors.toSet());
//Get values
Collection<String> values = parent.keySet().stream().map(HashMap::values).flatMap(Collection::stream).collect(Collectors.toList());
//Print key and values
keys.forEach(System.out::println);
values.forEach(System.out::println);
Result =
keys = a ,d
values = e , b
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 have map as below
Map<String, String> values = new HashMap<String, String>();
values.put("aa", "20");
values.put("bb", "30");
values.put("cc", "20");
values.put("dd", "45");
values.put("ee", "35");
values.put("ff", "35");
values.put("gg", "20");
I want to create new map in the format Map<String,List<String>> , sample output will be as
"20" -> ["aa","cc","gg"]
"30" -> ["bb"]
"35" -> ["ee","ff"]
"45" -> ["dd"]
I am able to do by iterating through entity
Map<String, List<String>> output = new HashMap<String,List<String>>();
for(Map.Entry<String, String> entry : values.entrySet()) {
if(output.containsKey(entry.getValue())){
output.get(entry.getValue()).add(entry.getKey());
}else{
List<String> list = new ArrayList<String>();
list.add(entry.getKey());
output.put(entry.getValue(),list);
}
}
Can this be done better using streams?
groupingBy can be used to group the keys by the values. If used without a mapping Collector, it will transform a Stream of map entries (Stream<Map.Entry<String,String>>) to a Map<String,List<Map.Entry<String,String>>, which is close to what you want, but not quite.
In order for the value of the output Map to be a List of the original keys, you have to chain a mapping Collector to the groupingBy Collector.
Map<String,List<String>> output =
values.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue,
Collectors.mapping(Map.Entry::getKey,
Collectors.toList())));
System.out.println (output);
Output :
{45=[dd], 35=[ee, ff], 30=[bb], 20=[aa, cc, gg]}
Note that in Java 8, you can also do better without using streams using Map.forEach and Map.computeIfAbsent. This way, it is more concise than the old version with Map.Entry<String, String>, entry.getValue(), entry.getKey() etc.
So you don't have to compare the old Java-7 iteration to that Java-8 stream solution, but to this one.
values.forEach( (key,value)->
groupBy.computeIfAbsent(value, x->new ArrayList<>())
.add(key)
);