final Set<Integer> set1 = new HashSet<>();
final Set<Integer> set2 = new HashSet<>();
Stream.of(set1, set2).mapToInt(???).forEach(intValue -> code)
I have 2 Set of Integer and in a Stream but i want to map them all into Integers. I can't find a way to do it using maptoInt or flatMap so i can extract all Integers of both Sets.
You can use Stream.concat(set1.stream(), set2.stream()) which creates a new combined stream so you can then map your values to int
Aside from stream concatenation mentioned at https://stackoverflow.com/a/65675352 you can also use
Stream.of(set1, set2)
.flatMap(set -> set.stream())
.mapToInt(i -> i)
.forEach(System.out::println);
since flatMap expects mapping to Stream of values which should be "used" by current stream.
So in your case you want stream containing values inside each set which can be created via
set -> set.stream()
or Set::stream.
Related
I have 2 arrays and want to make a list of role.getRoleName() only with elements that are in both arrays using streams.
final List<String> roleNames = new ArrayList<>();
roleNames = Arrays.stream(roles).filter(role -> role.getRoleId()
== Arrays.stream(permissions).map(permission -> permission.getRoleId()));
when I write the above code I get
Operator '==' cannot be applied to 'int', 'java.util.stream.Stream'
I understand the error, but I don't know the solution of how to make the permissions stream in only permission.getRoleId integers.
There is no way to compare such incompatible types as int and Stream.
Judging from what you've shown, Stream#anyMatch might a good candidate.
roleNames = Arrays.stream(roles)
.map(Role::getRoleId)
.filter(id -> Arrays.stream(permissions).map(Role::getRoleId).anyMatch(p -> p.equals(id)))
.collect(Collectors.toList());
This part Arrays.stream(permissions).map(Role::getRoleId) may be pre-calculated and stored into a Set.
final Set<Integer> set = Arrays.stream(permissions)
.map(Role::getRoleId)
.collect(Collectors.toSet());
roleNames = Arrays.stream(roles)
.filter(role -> set.contains(role.getRoleId()))
.map(Role::getRoleName)
.collect(Collectors.toList());
What you can do is collect unique roleIds for the array of Permissions into a Set as a computed result and perform a contains check as you iterate through the array of Roles. This could be done as :
final Set<Integer> uniqueRoleForPermissions = Arrays.stream(permissions)
.map(Permission::getRoleId)
.collect(Collectors.toSet());
final List<String> roleNames = Arrays.stream(roles)
.filter(role -> uniqueRoleForPermissions.contains(role.getRoleId()))
.map(Role::getRoleName)
.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 a Java bean, like
class EmployeeContract {
Long id;
Date date;
getter/setter
}
If a have a long list of these, in which we have duplicates by id but with different date, such as:
1, 2015/07/07
1, 2018/07/08
2, 2015/07/08
2, 2018/07/09
How can I reduce such a list keeping only the entries with the most recent date, such as:
1, 2018/07/08
2, 2018/07/09
?
Preferably using Java 8...
I've started with something like:
contract.stream()
.collect(Collectors.groupingBy(EmployeeContract::getId, Collectors.mapping(EmployeeContract::getId, Collectors.toList())))
.entrySet().stream().findFirst();
That gives me the mapping within individual groups, but I'm stuck as to how to collect that into a result list - my streams are not too strong I'm afraid...
Well, I am just going to put my comment here in the shape of an answer:
yourList.stream()
.collect(Collectors.toMap(
EmployeeContract::getId,
Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(EmployeeContract::getDate)))
)
.values();
This will give you a Collection instead of a List, if you really care about this.
You can do it in two steps as follows :
List<EmployeeContract> finalContract = contract.stream() // Stream<EmployeeContract>
.collect(Collectors.toMap(EmployeeContract::getId,
EmployeeContract::getDate, (a, b) -> a.after(b) ? a : b)) // Map<Long, Date> (Step 1)
.entrySet().stream() // Stream<Entry<Long, Date>>
.map(a -> new EmployeeContract(a.getKey(), a.getValue())) // Stream<EmployeeContract>
.collect(Collectors.toList()); // Step 2
First step: ensures the comparison of dates with the most recent one mapped to an id.
Second step: maps these key, value pairs to a final List<EmployeeContract> as a result.
Just to complement the existing answers, as you're asking:
how to collect that into a result list
Here are some options:
Wrap the values() into an ArrayList:
List<EmployeeContract> list1 =
new ArrayList<>(list.stream()
.collect(toMap(EmployeeContract::getId,
identity(),
maxBy(comparing(EmployeeContract::getDate))))
.values());
Wrap the toMap collector into collectingAndThen:
List<EmployeeContract> list2 =
list.stream()
.collect(collectingAndThen(toMap(EmployeeContract::getId,
identity(),
maxBy(comparing(EmployeeContract::getDate))),
c -> new ArrayList<>(c.values())));
Collect the values to a new List using another stream:
List<EmployeeContract> list3 =
list.stream()
.collect(toMap(EmployeeContract::getId,
identity(),
maxBy(comparing(EmployeeContract::getDate))))
.values()
.stream()
.collect(toList());
With vavr.io you can do it like this:
var finalContract = Stream.ofAll(contract) //create io.vavr.collection.Stream
.groupBy(EmployeeContract::getId)
.map(tuple -> tuple._2.maxBy(EmployeeContract::getDate))
.collect(Collectors.toList()); //result is list from java.util package
I have a database object that has a field that contains a list of strings. I retrieve all these objects and then use the flatMap and distinct stream methods on the resulting list to get a new list that holds all possible unique values that a database object string list can contain.
Next i want to make a map where the keys are the unique values list of the stringlist that i made earlier, and the values of the map are a list of database objects whose stringlist contains the value of the respective string mapkey.
So what I want is groupingBy the following:
if(object.stringList().contains(respectiveMapKeyFromUniqeStringCollection) put object in object values list of that respective keymap.
Is something like this possible using the groupingBy method?
Edit: I will explain further
class VegetableMaker{
#ElementCollection
private List<String> vegetableList;
}
Lets assume the possible values that a vegetableList can contain are: "Lettuce, Tomato, spinache, rubarbe, onion"
Set<String> produceNames = vegetableMakers.stream().flatMap(vegetableMaker -> vegetableMaker.getVegetableList().stream())
.distinct().collect(Collectors.toSet());
Now we have the list that contains all the possible values mentioned before.
We want to use the values in this list as the keys in the map.
So the Map will look like:
Map<uniqueStringsAsKeys, List<VegetableMaker>> map
The list value contains all the VegetableMaker instances of which the vegetableList contains the key of the map. So the list of key Onion will contain all the VegetableMaker instances whose list includes "Onion".
Is it possible to achieve such a map using the groupingBy method of a java stream?
EDIT 2:
This is the solution i have now, that doesn't use groupingBy but clarifies even more what I want.
EDIT: changed variable in code to match variables used in previous examples.
Set<VegetableMaker> vegetableMakers = vegetableMakerDao.findAll();
Set<String> uniqueVegetableList = vegetableMakers.stream().flatMap(vegetableMaker -> affiliateLink.getKeywords().stream()).distinct().collect(Collectors.toSet());
Map<String,Set<VegetableMaker>> vegetableMakersContainingKeywordInTheirList = new HashMap<>();
uniqueVegetableList.forEach(produceName ->{
Set<VegetableMaker> vegetableMakerSet = new HashSet<>();
vegetableMakers.forEach( vegetableMaker -> {
if(vegetableMaker.getVegetableList().contains(produceName))
vegetableMakerSet.add(vegetableMaker);
});
vegetableMakersContainingKeywordInTheirList.put(produceName, vegetableMakerSet);
});
If I understood you correctly:
List<VegetableMaker> dbObjects = List.of(
new VegetableMaker("Salad", List.of("Onion", "Cucumber")),
new VegetableMaker("Italian Salad", List.of("Cheese")),
new VegetableMaker("Greek Salad", List.of("Onion")));
Map<String, List<VegetableMaker>> map = dbObjects.stream()
.flatMap(x -> x.getVegetableList().stream().map(y -> new SimpleEntry<>(x, y)))
.collect(Collectors.groupingBy(
Entry::getValue,
Collectors.mapping(Entry::getKey, Collectors.toList())));
System.out.println(map);
Resulting being something like:
{Onion=[Salad, Greek Salad], Cheese=[Italian Salad], Cucumber=[Salad]}
EDIT
This is not much different than what I posted above:
Map<String, Set<VegetableMaker>> result = vegetableMakerList.stream()
.flatMap(x -> x.getKeywords().stream().distinct().map(y -> new SimpleEntry<>(x, y)))
.collect(Collectors.groupingBy(
Entry::getValue,
Collectors.mapping(Entry::getKey, Collectors.toSet())));
final Set<VegetableMaker> vegetableMakers = vegetableMakerDao.findAll();
final Map<String, Set<VegetableMaker>> vegetableMakersContainingKeywordInTheirList = vegetableMakers.stream()
.map(VegetableMaker::getKeywords)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toMap(
Function.identity(),
vegetable -> vegetableMakers.stream()
.filter(vegetableMaker -> vegetableMaker.getKeywords().contains(vegetable))
.collect(Collectors.toSet())
));
I have a Map of Lists, and would like to collect all the values and then stream on the collected List, so given:-
Map<LocalDateTime, List<PublicationSession>> effectiveDatePublicationMap;
Below works / shows what I want to do with iteration but I want to do this all in streams, rather than creating an intermediate list using iteration:-
List< PublicationSession> publicationsToFilter = new ArrayList<>();
for (List< PublicationSession> sessions : effectiveDatePublicationMap.values()) {
publicationsToFilter.addAll(sessions);
}
Collection< PublicationSession > wantedPublications = publicationsToFilter.stream()
.filter(pub -> PublicationStatus.valueOf(pub.getPublishStatus()) == PublicationStatus.COMPLETE)
.sorted(Comparator.comparing(PublicationSession::getCreateTime))
.collect(toMap(p -> p.getPublicationSession().getEffDateTime(), UnaryOperator.identity(), PICK_LATEST))
.values();
So I wanted to stream the map of lists all into one lists, then work on that sublist in one stream rather than having to do the above in two statements (ie build up the list by iteration, then do the streaming to filter / sort and collect.
I have so far failed to do so, when I try and stream / collect the map I get compile issues. Could anyone show how to do the above in one step, without having to do iteration then streaming?
It looks like all you need is flatMap the values of the original Map and then continue processing as you currently do:
Collection< PublicationSession > wantedPublications =
effectiveDatePublicationMap.values() // Collection<List<PublicationSession>>
.stream() // Stream<List<PublicationSession>>
.flatMap(list->list.stream()) // Stream<PublicationSession>
.filter(pub -> PublicationStatus.valueOf(pub.getPublishStatus()) == PublicationStatus.COMPLETE)
.sorted(Comparator.comparing(PublicationSession::getCreateTime))
.collect(toMap(p -> p.getPublicationSession().getEffDateTime(), UnaryOperator.identity(), PICK_LATEST))
.values();
To obtain the same result of your iterative code
List< PublicationSession> publicationsToFilter = new ArrayList<>();
for (List< PublicationSession> sessions : effectiveDatePublicationMap.values()) {
publicationsToFilter.addAll(sessions);
}
with streams you first have to use flatMap to transoform your stream of List<PublicationSession> in a stream of PublicationSession, and then collect all of them in a list with collect(Collectors.toList())
List<PublicationSession> publicationsToFilter = effectiveDatePublicationMap.values()
.flatMap(Collection::stream)
.collect(Collectors.toList());
Before collecting the result, you can filter or sort as you wish.