How this can be replaced with collect?
List<Serializable> result = new ArrayList<>();
entries.forEach(entry-> result.add(session.save(entry)));
That's pretty straight forward :
List<Serializable> result =
entries.stream()
.map(session::save)
.collect(Collectors.toList());
The map method maps the input entries into Serializable instances by calling session::save, and then all you need to do is collect them to a List.
Related
I have a map with a pet owner's name for key and a List of pets for a value.
I want to get the names of the people who have a hamster.
Map<String, List<String>> map = new HashMap<>();
List<String> list = new ArrayList<>();
list.add("dog");
map.put("Pesho", list);
list.clear();
list.add("dog");
list.add("cat");
map.put("Anne", list);
list.clear();
list.add("iguana");
list.add("hamster");
list.add("turtle");
map.put("Kate", list);
// The stream only returns if someone in the map has a hamster
System.out.println(map.values().stream()
.anyMatch(pets -> pets.contains("hamster")));
Iteration needs to be done over the entry set or over the key set, it is impossible to access a key when have only a value.
Operation anyMatch() returns a boolean value. You need to use either findFirst() to get a single result, or collect() to obtain a collection of names. In both cases, the predicate from the anyMatch() needs to be placed into the filter() operation.
Terminal operation findFirst() returns Optional because a result might not be present. You can extract a value from the optional in different ways, for instance, by applying get(), but in the case of empty optional it'll throw NoSuchElementException. In the example below, method orElse() is used to provide a default value.
String name =
map.entrySet().stream() // stream of map-entries
.filter(entry -> entry.getValue().contains("hamster"))
.map(Map.Entry::getKey)
.findFirst()
.orElse("no owner was found");
Operation collect() expects as a parameter Collector (an object that is responsible for populating a mutable container, like a collection with elements of the stream).
List<String> names =
map.keySet().stream() // stream of owner names
.filter(key -> map.get(key).contains("hamster"))
.collect(Collectors.toList()); // Or `toList()` in Java 16+.
Note:
When the two entries in your code will share the same list. Instead of invoking list.clear(); need to create a new list so that every key will correspond to a distinct collection of pet-names.
Search will be more performant if you replace an ArrayList with a HashSet (i.e. map will be declared as Map<String,Set<String>>).
Collection<Map<String, MyObj>>
I need to collect list of MyObj from above structure.
For instance I also had Collection<MyObj> - in this for collecting list of MyObj I did below
List<MyObj> result = new ArrayList<>(MyObj);
works fine.
How do I achieve similar result from Collection<Map<String, MyObj>>?
So you want to flatten the maps to a single list of values? You can use streams to do this pretty easily:
List<MyObj> list = collection.stream()
.map(Map::values)
.flatMap(Collection::stream)
.collect(Collectors.toList());
You can do:
List<MyObj> result = collections.stream()
.flatMap(m->m.values().stream())
.collect(toList());
Try this:
Takes the map values and streams them and collects them into a list.
List<MyObj> obList = origList.stream()
.flatMap(m->m.values().stream())
.collect(Collectors.toList());
I am new to Java streams and have a problem at hand. I have a map like this:
Map<String, List<String>> specialProductsMap
And i want to flatten the map values to a set which contains all the String values in lists in the specialProductsMap. How can i do this using Java Streams?
You may use the flatMap operator to get this thing done. Here's how it looks.
Set<String> valueSet = specialProductsMap.values().stream()
.flatMap(List::stream)
.collect(Collectors.toSet());
First Obtain the list of values from map then use stream api like this
Set<String> setOfString = specialProductsMap.values().stream().flatMap(list->list.stream())
.collect(Collectors.toSet());
Or Like this Using Method reference
Set<String> setOfString = specialProductsMap.values().stream().flatMap(List::stream)
.collect(Collectors.toSet());
You have to stream your values :
Stream<List<String>> myStream = specialProductsMap.values().stream();
Then flatten it :
Stream<String> myData = myStream.flatMap(List::stream);
Then collect in a set :
Set<String> = myData.collect(Collectors.toSet());
I have the list as follows:
List<Map<String,Object>> mapList=new ArrayList<>();
Map<String,Object> mapObject=new HashMap<String,Object>();
mapObject.put("No",1);
mapObject.put("Name","test");
mapList.add(mapObject);
Map<String,Object> mapObject1=new HashMap<String,Object>();
mapObject1.put("No",2);
mapObject1.put("Name","test");
mapList.add(mapObject1);
and so on...
Now I want to get all the values of the key "No" as a string seperated by comma as follows:
String noList="1,2,3"
Can anyone please suggest me what may best way to do it. I know we can do it by looping but instead of looping is any other ways to do it.
Explanations inline!
mapList.stream() // stream over the list
.map(m -> m.get("No")) // try to get the key "No"
.filter(Objects::nonNull) // filter any null values in case it wasn't present
.map(Object::toString) // call toString for each object
.collect(Collectors.joining(",")); // join the values
Simply map the list:
String list = mapList.stream()
.filter(x -> x.containsKey("No")) // get only the maps that has the key
.map(x -> x.get("No").toString()) // every map will be transformed like this
.collect(Collectors.joining(",")); // joins all the elements with ","
System.out.println(list);
The use of HashMap<String, Object> suggests that it might be better to create a new class for this data. Have you considered this possibility before?
You can loop like this:
List<String> noList = new ArrayList<>(mapList.size());
for (Map<String,Object> m : mapList) {
Optional.ofNullable(m.get("No")) // get value mapped to "No" or empty Optional
.map(Object::toString)
.ifPresent(noList::add); // if not empty, add to list
}
System.out.println(String.join(",", noList));
or internally (the officially preferred version IIRC):
List<String> noList = new ArrayList<>(mapList.size());
mapList.forEach(m ->
Optional.ofNullable(m.get("No")).map(Object::toString).ifPresent(noList::add));
System.out.println(String.join(",", noList));
Now that I think of it, it's shorter than the Stream version.
Answered a pretty similar question 30 minutes ago.
You are using repeated keys. This makes it look like you don't need maps, but a class with the attributes "No", "Name", etc. If you've this class you can just iterate your instances on the list and concatenating to a String.
If no matter what you want to have your maps, simply get the values of the "No" key, but note that this is a wrong practise and you should be probably using a class instead of maps:
String res = "";
for(int i = 0; i < mapList.size(); i++) {
Map<String,Object> map = mapList.get(i);
res.concat(map.get("No"));
if(i != mapList.size() - 1)
res.concat(",");
}
PS: If you are going with the bad solution practise, use the stream alternatives in the other answers if your knowledge of stream is enough to understand them.
I have a Map<String, List<String>>. I want to transform this map to a List after filtering on the map's key.
Example:
Map<String, List<String>> words = new HashMap<>();
List<String> aList = new ArrayList<>();
aList.add("Apple");
aList.add("Abacus");
List<String> bList = new ArrayList<>();
bList.add("Bus");
bList.add("Blue");
words.put("A", aList);
words.put("B", bList);
Given a key, say, "B"
Expected Output: ["Bus", "Blue"]
This is what I am trying:
List<String> wordsForGivenAlphabet = words.entrySet().stream()
.filter(x-> x.getKey().equalsIgnoreCase(inputAlphabet))
.map(x->x.getValue())
.collect(Collectors.toList());
I am getting an error. Can someone provide me with a way to do it in Java8?
Your sniplet wil produce a List<List<String>> not List<String>.
You are missing flatMap , that will convert stream of lists into a single stream, so basically flattens your stream:
List<String> wordsForGivenAlphabet = words.entrySet().stream()
.filter(x-> x.getKey().equalsIgnoreCase(inputAlphabet))
.map(Map.Entry::getValue)
.flatMap(List::stream)
.collect(Collectors.toList());
You can also add distinct(), if you don't want values to repeat.
Federico is right in his comment, if all you want is to get the values of a certain key (inside a List) why don't you simply do a get (assuming all your keys are uppercase letters already) ?
List<String> values = words.get(inputAlphabet.toUpperCase());
If on the other hand this is just to understand how stream operations work, there is one more way to do it (via java-9 Collectors.flatMapping)
List<String> words2 = words.entrySet().stream()
.collect(Collectors.filtering(x -> x.getKey().equalsIgnoreCase(inputAlphabet),
Collectors.flatMapping(x -> x.getValue().stream(),
Collectors.toList())));
As was previously told after collect you will get List<List<String>> with only one or zero value in it. You can use findFirst instead of collect it will return you Optional<List<String>>.