How do I create HashMap of String and List of String out of Set of String with Stream?
Set<String> mySet;
Map<String, List<String>> = mySet.stream().map(string -> {
// string will be my key
// I have here codes that return List<String>
// what to return here?
}).collect(Collectors.toMap(.....)); // what codes needed here?
Thank you.
You don't need the map() step. The logic that produces a List<String> from a String should be passed to Collectors.toMap():
Map<String, List<String>> map =
mySet.stream()
.collect(Collectors.toMap(Function.identity(),
string -> {
// put logic that returns List<String> here
}));
The map operation is useless here, because you don't want to change the string itself, or you would have to map it to an Entry<String, List<String>> and then collect them, but this is not easier.
Instead just build the map, the string as key and get your codes as values :
Map<String, List<String>> map =
mySet.stream().collect(Collectors.toMap(str->str, str-> getCodesFromStr(str));
If you want to know, how it would be with a map operation and use Entry (a pair) :
Map<String, List<String>> = mySet.stream().map(str->
new AbstractMap.SimpleEntry<String,List<String>>(str, getCodesFromStr(str))
).collect(Collectors.toMap(Entry::getKey, Entry::getValue));
Related
I have a nested String HashMap and a List of object. The object has a String property to be matched against the values of the inner HashMap.
I'm trying to find a single liner using stream() and Collectors for the below java code
HashMap<String, HashMap<String, String>>PartDetailsHMap=new HashMap<String, HashMap<String, String>>()
List<Part> partList=new ArrayList<Part>();
for(int i=0;i<partList.size();i++)
String partId = partList.get(i).getPropertyValue("part_id");
for(HashMap< String, String> PartPropsHMap:PartDetailsHMap.values())
{
if(PartPropsHMap.containsValue(itemId))
{
collectingPartMap.put(partList.get(i), PartPropsHMap);
break;
}
}
}
If needed I can extract String property in a List<String>.
Looking for a one liner using stream().
Something like this should work:
Map<String, Map<String, String>> PartDetailsHMap = new HashMap<>();
List<Part> partList = new ArrayList<>();
Map<Part, Map<String, String>> collectingPartMap = partList.stream()
.map(part -> PartDetailsHMap.values()
.stream()
.filter(partPropsHMap -> partPropsHMap.containsValue(part.getPropertyValue("part_id")))
.findFirst()
.map(partPropsHMap -> new SimpleEntry<Part, Map>(part, partPropsHMap))
.get()
)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
I've used SimpleEntry class in AbstractMap to carry the context of Part along with the map that we've found to the next operation - collect.
Caveat: I feel if the option without streams is cleaner and does the job, I would go with that. Given that the manipulation you need here is fairly involved, it would benefit in the long run to keep it readable, than something clever.
An alternate approach slightly improving the current answer could be to not perform a get without an isPresent check. This could be achieved by using filter and map
Map<Part, Map<String, String>> collectingPartMap = partList.stream()
.map(part -> partDetailsHMap.values().stream()
.filter(innerMap -> innerMap.containsValue(part.getPartId())) // notice 'getPartId' for the access
.findFirst()
.map(firstInnerMap -> new AbstractMap.SimpleEntry<>(part, firstInnerMap)))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
I want to convert from Collection<Map<String,String>> to Map<String,String>.
When I tried to do this way,
Map<String,String> m = (Map<String,String>)map.values();
where,
map is of type Map<String,Map<String,String>>
I'm getting
java.lang.ClassCastException: java.util.TreeMap$Values cannot be cast to java.util.Map
What is it trying to say? I'm not able to get it and how do I correctly convert from Collection<Map<String,String>> to Map<String,String>?
You can use this small snippet to put all the values into a single map:
Map<String, String> result = new TreeMap<>();
for(Map<String, String> value : map.values()) {
result.putAll(value);
}
Though this will just overwrite duplicate keys with a new value if there are any.
As long as it's collection then you should think as it's collection of objects.
Then proceed the iteration, for each object, you shall put it in the map
public Map<String, String> getMapsFromArrayOfMaps( Collection<Map<String,String>> maps ) {
Map<String, String> result = new HashMap<>();
maps.forEach(map->result.putAll(map));
return result ;
}
I have a file that i get all the data and separate it into a HashMap.
The file looks something like this below.
Before the : is the key and after is the value
key1: 1
key2: 2
key3: 3
this is the code that puts the file data into the map ArrayList:
protected List<Map<String, String>> yaml_parse(BufferedReader filename) throws IOException{
String result;
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
while ((result = filename.readLine()) != null) {
Map<String, String> map = new HashMap<String, String>();
String key = result.substring(0, result.indexOf(":"));
String value = result.substring(result.lastIndexOf(":") + 2);
map.put(key, value);
list.add(map);
}
return list;
}
in another class where i call the function and println, this is the output
[{key1=1}, {key2=2}, {key3=3}]
So my Main question is, how do i get key1 and have it return its value?
I don't understand why you are creating a List of maps. A Map will let you put several key value pairs. Here is a way that would work:
protected Map<String, String> yaml_parse(BufferedReader filename) throws IOException{
String result;
Map<String, String> map = new HashMap<String, String>();
while ((result = filename.readLine()) != null) {
//keyValue[0] = key, keyValue[1] = value
String[] keyValue = result.split(": ");
map.put(keyValue[0], keyValue[1]);
}
return map;
}
And you would use it like this:
Map<String, String> map = yaml_parse("myFile.yaml");
String key1Value = map.get("key1"); //Stores key1's value into key1Value
I think you might be using the wrong data structure. From your question, it seems like you want a Map only, not a List of Maps.
You should look at changing your List<Map> to a Map. You can do this using:
Map<String, String> map = list.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
If you want to work with your current data structure, you can get the required value like this:
private Optional<String> getValue(List<Map<String, String>> list, String key) {
return list.stream()
.filter(m -> m.containsKey(key))
.map(m -> m.get(key))
.findFirst();
}
and use it as follows:-
Optional<String> value = getValue(list, "key2");
System.out.println(value.orElse(null));
So if you are interested in using java-8, if list of map contains any of entry with key as key1 will return the first entry value else it will return the default value
list.stream().flatMap(map->map.entrySet().stream().filter(entry->entry.getKey().equals("key1"))).findFirst()
.orElse(new AbstractMap.SimpleEntry("key1", "default value")).getValue();
Just by using normal for loop
for(Map<String, String> map : list) {
if(map.containsKey("key1")) {
result = map.get("key1");
break;
}
}
Are you sure this is the data structure you want?
A map can contain more than 1 key/value pair. Why not have a single hashmap here, containing all 3 key/value pairs, at which point, you can just do:
map.get("key1")
and it'll still be fast even if you have millions of these.
If you are making single-size maps and putting them into an arraylist because you want to preserve order, use LinkedHashMap. If you need to be capable of dealing with repeated keys, use guava's Multimap, or make a Map<String, List<String>>.
The input is a hash map, such like
HashMap<String, String> hashmap = new HashMap<String, String>();
for (Map.Entry<String, String> entry : hashmap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
}
I would like to write a method that return list of type Class A, which had key, value attributes with String type, and the key-value from hashmap.
How to make it real?
If you are using Java 8, you could do something like this:
List<Entry<String, String>> list = hashmap
.entrySet() // Get the set of (key,value)
.stream() // Transform to a stream
.collect(Collectors.toList()); // Convert to a list.
If you need a list of elements of type A, you can adapt:
List<A> list = hashmap
.entrySet() // Get the set of (key,value)
.stream() // Transform to a stream
.map(A::new) // Create objects of type A
.collect(Collectors.toList()); // Convert to a list.
assuming that you have a constructor in A that looks like that:
A(Map.Entry<String,String> e){
this.key=e.getKey();
this.value=e.getValue();
}
I hope it helps.
List<A> listOfA= new ArrayList<>();
for (Map.Entry<String, String> entry : hashmap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
A aClass = new A(key, value);
listOfA.add(aClass);
}
return listOfA;
I have the following Object and a Map:
MyObject
String name;
Long priority;
foo bar;
Map<String, List<MyObject>> anotherHashMap;
I want to convert the Map in another Map. The Key of the result map is the key of the input map. The value of the result map ist the Property "name" of My object, ordered by priority.
The ordering and extracting the name is not the problem, but I could not put it into the result map. I do it the old Java 7 way, but it would be nice it is possible to use the streaming API.
Map<String, List<String>> result = new HashMap<>();
for (String identifier : anotherHashMap.keySet()) {
List<String> generatedList = anotherHashMap.get(identifier).stream()...;
teaserPerPage.put(identifier, generatedList);
}
Has anyone an idea? I tried this, but got stuck:
anotherHashMap.entrySet().stream().collect(Collectors.asMap(..., ...));
Map<String, List<String>> result = anotherHashMap
.entrySet().stream() // Stream over entry set
.collect(Collectors.toMap( // Collect final result map
Map.Entry::getKey, // Key mapping is the same
e -> e.getValue().stream() // Stream over list
.sorted(Comparator.comparingLong(MyObject::getPriority)) // Sort by priority
.map(MyObject::getName) // Apply mapping to MyObject
.collect(Collectors.toList())) // Collect mapping into list
);
Essentially, you stream over each entry set and collect it into a new map. To compute the value in the new map, you stream over the List<MyOjbect> from the old map, sort, and apply a mapping and collection function to it. In this case I used MyObject::getName as the mapping and collected the resulting names into a list.
For generating another map, we can have something like following:
HashMap<String, List<String>> result = anotherHashMap.entrySet().stream().collect(Collectors.toMap(elem -> elem.getKey(), elem -> elem.getValue() // can further process it);
Above I am recreating the map again, but you can process the key or the value according to your needs.
Map<String, List<String>> result = anotherHashMap.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().stream()
.sorted(comparing(MyObject::getPriority))
.map(MyObject::getName)
.collect(Collectors.toList())));
Similar to answer of Mike Kobit, but sorting is applied in the correct place (i.e. value is sorted, not map entries) and more concise static method Comparator.comparing is used to get Comparator for sorting.