List containing another list to set using lambda in java - java

I have a list containing Persons, each person has a list with his subjects inside.
I need to return a Set containing every subject using lambda, so far i've tried this:
list.stream().map(person -> person.getSubjects());
But that would get me a List> so i can't use it.
How could i print/get every string in the list of every person using lambdas?
Thanks.

list.stream().map(person -> person.getSubjects().stream()); is not a List, it's a Stream. If you want a Set, do this :
list.stream().flatMap(person -> person.getSubjects().stream()).collect(Collectors.toSet());
This will create an HashSet<Subject>. Note the use of flatMap instead of map to flatten the lists of subjects into a single stream. If you want another implementation of Set, for example TreeSet, do the following :
list.stream().flatMap(person -> person.getSubjects().stream())
.collect(Collectors.toCollection(TreeSet::new));

You can use flatMap:
Set<Subject> subjects = list.stream()
.map(person -> person.getSubjects())
.flatMap(subjects -> subjects.stream())
.collect(Collectors.toSet());
flatMap is good for "flattening" nested collections.

Related

Correct use of Java 8 supplier consumer

I'm still strugling with Suppliers and Consumers for Java 8, I have this:
final Set<String> roles = new HashSet<>();
user.getRoleGroups().forEach(rg -> rg.getRoles().forEach(r -> roles.add(r.getName())));
To get a Set from role names that are inside a list of Roles inside a list of RoleGroups.
Pretty sure I could use something in one line with .stream().map() and RoleGroup::getRoles and Role::getName to get this Set. But I don't know how.
You are pretty close! To use a Stream instead, do something like this:
final Set<String> roles = user.getRoleGroups().stream()
.flatMap(g -> g.getRoles().stream())
.map(Role::getName)
.collect(Collectors.toSet());
Use of flatMap() is the only tricky part here. The flatMap() operation transforms an element to a Stream, which is concatenated with the Streams from the other elements.

How do I simultaneously iterate through a list and a set while pairing them in another map (using stream)

What i've tried is creating an iterator for the list and using stream on the set as such
Set //some object which has a getId method
Iterator<String> iterator = list.iterator();
someSet.stream()
.map(Collectors.toMap(e -> e.getId(), e -> iterator.next() );
The Stream API is designed to work and iterate through one and only one collection and no more.
If you want to achieve such iteration called "zipping", as mentioned in the another answer, you have to iterate the indices. Since Set is not ordered, you have to use List instead and know the order is not predictable.
However, the usage of Stream API should be fine here:
Set<MyObject> set = ... // MyObject with getId method
List<MyObject> listFromSet = new ArrayList<>(set);
List<MyObject> list = ... // existing list
IntStream.range(0, Math.min(list.size(), listFromSet.size()))
.mapToObj(index -> new AbstractMap.SimpleEntry<>(
listFromSet.get(index).getId(), // key
list.get(index)) // value
)
.collect(Collectors.toMap(Entry::getKey, Entry::getValue)); // to Map
Few notes:
To know the highest number you can iterate through, you need ti find a lower from the sizes of the iterables: Math.min(list.size(), listFromSet.size()).
map(Collector.toMap(...)) doesn't convert a Stream to Map but is not a valid construct, moreover the method map is not a terminal operation. Use .collect(Collectors.toMap(...)) instead which is.
Not all the keys from set might be used, not all the values from list might be used, there is no guaranteed order of the keys and the matching key-value will be random.
If I were to implement this, I'd definetly go for the simple for-loop iteration over the Streams.
I think, what you wat to achieve is called "zip" in fuctional programming. This would be in Java to make a new stream from two existing streams by combining each of two corresponding elements of the given streams.
Look at this question to see how to do it:
Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip)

Return specific object from an ArrayList

I have a ArrayList with thousands of properties with many variables(including city). I need access/return only the properties from a specific city e.g all properties from Surrey. How do i get them?
I know how to search for them, by doing city.values("Surrey"). But I do not know how output the values.
I assume you want to search in your AirbnbListing list. You can use Java Stream. Use the filter method for that:
List<AirbnbListing> matchingListings = listings.stream()
.filter(l -> "Surrey".equals(l.getCity()))
.collect(Collectors.toList());
If you want a list of all cities, you can use the map method:
List<String> matchingListings = listings.stream()
.map(l -> l.getCity())
.collect(Collectors.toList());
Additionally here is an official Java stream explanation tutorial.
If you are using Java 8 or higher there is following option:
list.stream().filter(x -> "Berlin".equals(x.getCity())); //This filters the list and returns a list with city = Berlin.
Hopefully this is what you are looking for.

Cactoos flatMap analogy

Is there flatMap analogy in Cactoos library? I need exactly what flatMap can, but without streams:
The flatMap() operation has the effect of applying a one-to-many transformation to the elements of the stream, and then flattening the resulting elements into a new stream.
E.g. if I have some values in list, and each value has children items, and I want to get all items from each value, I can use flatMap:
List<Value> values = someValues();
List<Item> items = values.stream()
.flatMap(val -> val.items().stream()) // val.items() returns List<Item>
.collect(Collectors.toList());
How to do the same thing using Cactoos instead of streams API?
You can use Joined, it is the equivalent of flattening an Iterable.
For example, you would write:
new Joined<>(new Mapped<>(val -> val.items(), someValues()));

Collect all values of a Set field

I have a collection which has a field of type Set with some values. I need to create a new set collecting all these values.
I am wondering if this is possible using lambda expressions.
Below is the code line :
Set<String> teacherId = batches.stream()
.filter(b -> !CollectionUtils.isEmpty(b.getTeacherIds()))
.map(b -> b.getTeacherIds())
.collect(Collectors.toSet());
The problem is post map operation, it contains a collection of set of strings. So collect operation returns a Set<Set<String>> but i am looking to aggregate all the values to a single set.
You need to use flatMap instead of map:
Set<String> teacherIds =
batches.stream()
.flatMap(b -> b.getTeacherIds().stream())
.collect(Collectors.toSet());
Note that the filtering is redundant for empty collections - streaming an empty collection will just result in an empty stream, which won't affect the final result.
If getTeacherIds() could return null, however, you'd still have to handle it. Using filter(Objects::nonNull) would suffice, and save you the dependency on Apache Commons.
You can use flatMap to obtain a flat Stream of all the values, and then collect to a Set<String>:
Set<String> teacherId =
batches.stream()
.filter(b -> !CollectionUtils.isEmpty(b.getTeacherIds()))
.flatMap(b -> b.getTeacherIds().stream())
.collect(Collectors.toSet());
If you care that that getTeacherIds() is not null, use it explicitly via !=, that CollectionUtils.isEmpty just hides stuff. Especially since if getTeacherIds() returns an Empty collection - that is handled just fine by flatMap, so to me that is not needed at all.
Set<String> teacherIds = batches
.stream()
.filter(x -> x.getTeacherIds() != null)
.flatMap(x -> x.getTeacherIds().stream())
.collect(Collectors.toSet());
I am wondering if this is possible using lambda expressions.
I capture the last fish, :).
Set<String> teacherIds = batches.stream()//v--- the class of `x`
.map(XClass::getTeacherIds)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
Note: I'm sorry I'm forget to tell you if the getTeacherIds copy the internal IDs to a new set of IDs, the code above is appropriate for you. since it is read the IDs from XClass once.

Categories

Resources