I have googled quite a bit, but didn't found an answer.
Here is what I have:
parentList.forEach(p -> {
childList
.stream()
.filter(c -> p.id() == c.parentId())
.<...continue working on stream...>
});
I cannot find a way how to replace "filter" part with a Predicate as it seems that I need to pass argument to Predicate?
Your problem is that you're using a different Predicate each time, because although c is the parameter to your predicate, p also varies:
final Node p;
Predicate<Node> matchesParentId = c -> p.id() == c.id();
The reason your existing code compiles OK is that p is effectively final in the scope of the forEach block, so it can be used as a final field in a Predicate within that scope, with a lifetime of one forEach iteration.
You could do:
parentList.forEach(p -> {
childList
.stream()
.filter(matchesId(p))
.<...continue working on stream...>
});
private Predicate<Node> matchesId(Node other) {
return node -> node.id() == other.id();
}
But you won't be able to create one Predicate and reuse it as p varies.
You could write a BiPredicate and curry it into a Predicate. Unfortunately Java doesn't provide a curry method, so you have to provide your own.
private <T,U> Predicate<U> curry(BiPredicate<T,U> biPredicate, T t) {
return u -> biPredicate.test(t, u);
}
BiPredicate<Node,Node> nodesMatch = (a,b) -> a.id() == b.id();
parentList.forEach(p -> {
childList
.stream()
.filter(curry(nodesMatch, p))
.<...continue working on stream...>
});
This doesn't buy you all that much over and above the previous solution, but it's a bit more FP-nerdy. You're still creating a new Predicate for every p. Of course you could inline it rather than use the curry() method.
.filter(c -> nodesMatch.test(p, c))
It does mean you could have a selection of BiPredicate<Node,Node>s to plug in dynamically. If your BiPredicate were expensive to initialise, the many Predicates wrapped around it by currying would be cheap.
Or, you could map p and c into a single object, which allows you to submit the whole thing to a predicate:
Predicate<Pair<Node,Node>> nodesMatch = pair ->
pair.left().id() == pair.right().id();
parentList.forEach(p -> {
childList
.stream()
.map(c -> new Pair<Node>( c, p))
.filter(nodesMatch)
.map( pair -> pair.left() )
.<...continue working on stream...>
});
(Pair here is hypothetical, but a number of 3rd party libraries (e.g. Guava) provide one, or roll your own, or use new Node[] { c, p })
Related
Based on some sports results data, I have a Fixture object which has getHome() and getAway() method. I'd like to shorten this method which I've written to only use a single lambda function (instead of creating a new list and two lambdas), is this possible?
private Collection<FixtureResult> finalResults(Team team) {
List<FixtureResult>finalResults = new ArrayList<>();
List<FixtureResult> homeResults = resultList.stream().filter(fixture ->
fixture.getHome().equals(team))
.collect(toList());
List<FixtureResult> awayResults = resultList.stream().filter(fixture ->
fixture.getAway().equals(team))
.collect(toList());
finalResults.addAll(homeResults);
finalResults.addAll(awayResults);
return finalResults;
}
Simple enough
resultList.stream()
.filter(fixture -> fixture.getHome().equals(team) || fixture.getAway().equals(team)))
.collect(toList());
EDIT: This is on the assumption that order does not matter to you. If your final list needs to have home result and then away, have a look at Elliott Frisch's answer.
If you wan to get fancy with lambdas:
Predicate<FixtureResult> isHome = fr -> fr.getHome().equals(team)
Predicate<FixtureResult> isAway = fr -> fr.getAway().equals(team)
resultList.stream()
.filter(isHome.or(isAway))
.collect(toList()));
You could even extract the compose predicate to test it in isolation, with no streams involved, which is good for more complex predicates:
Predicate<FixtureResult> isHomeOrAway = isHome.or(isAway)
assertTrue(isHomeOrAway(homeFixture));
...
Assuming the order doesn't matter, you can do it on one line. Like,
private Collection<FixtureResult> finalResults(Team team) {
return resultList.stream()
.filter(fixture -> fixture.getHome().equals(team)
|| fixture.getAway().equals(team))
.collect(toList());
}
If the order matters (home results and then away), you can do it with a single List like
private Collection<FixtureResult> finalResults(Team team) {
List<FixtureResult> al = new ArrayList<>(resultList.stream()
.filter(fixture -> fixture.getHome().equals(team)).collect(toList()));
al.addAll(resultList.stream()
.filter(fixture -> fixture.getAway().equals(team)).collect(toList()));
return al;
}
You can simply create a conditions concatenations or can concatenate multiple filter call
Conditions concatenations
myList.stream()
.filter(element -> (condition1 && condition2 && condition3))
Multiple filter call
myList.stream()
.filter(element -> condition1)
.filter(element -> condition2)
.filter(element -> condition3)
You can do the following
someStream.filter(((Predicate<SomeClass>) someObject-> someCondition).or(someObject-> someOtherCondition))
Or you can define your own "or" function that won't cause such a deep hierarchy
#SuppressWarnings("unchecked")
<R> Predicate<R> or(Predicate<R> ...predicates) {
return r -> Arrays.stream(predicates).anyMatch(p -> p.test(r));
}
That gives you a cleaner interface without casting and the nesting
.filter(or(
yourObject -> {
return false;
},
yourObject -> {
return false;
},
yourObject -> {
return false;
},
yourObject -> {
return false;
}
))
I need to create all possible combinations of some kind of Key, that is composed from X (in my case, 8), equally important elements. So i came up with code like this:
final LinkedList<Key> keys = new LinkedList();
firstElementCreator.getApplicableElements() // All creators return a Set of elements
.forEach( first -> secondElementCreator.getApplicableElements()
.forEach( second -> thirdElementCreator.getApplicableElements()
// ... more creators
.forEach( X -> keys.add( new Key( first, second, third, ..., X ) ) ) ) ) ) ) ) );
return keys;
and it's working, but there is X nested forEach and i have feeling that i'm missing out an easier/better/more elegant solution. Any suggestions?
Thanks in advance!
Is it Cartesian Product? Many libraries provide the API, for example: Sets and Lists in Guava:
List<ApplicableElements> elementsList = Lists.newArrayList(firstElementCreator, secondElementCreator...).stream()
.map(c -> c.getApplicableElements()).collect(toList());
List<Key> keys = Lists.cartesianProduct(elementsList).stream()
.map(l -> new Key(l.get(0), l.get(1), l.get(2), l.get(3), l.get(4), l.get(5), l.get(6), l.get(7))).collect(toList());
Since the number of input sets is fixed (it has to match the number of arguments in the Key constructor), your solution is actually not bad.
It's more efficient and easier to read without the lambdas, though, like:
for (Element first : firstElementCreator.getApplicableElements()) {
for (Element second : secondElementCreator.getApplicableElements()) {
for (Element third : thirdElementCreator.getApplicableElements()) {
keys.add(new Key(first, second, third));
}
}
}
The canonical solution is to use flatMap. However, the tricky part is to create the Key object from the multiple input levels.
The straight-forward approach is to do the evaluation in the innermost function, where every value is in scope
final List<Key> keys = firstElementCreator.getApplicableElements().stream()
.flatMap(first -> secondElementCreator.getApplicableElements().stream()
.flatMap(second -> thirdElementCreator.getApplicableElements().stream()
// ... more creators
.map( X -> new Key( first, second, third, ..., X ) ) ) )
.collect(Collectors.toList());
but this soon becomes impractical with deep nesting
A solution without deep nesting requires elements to hold intermediate compound values. E.g. if we define Key as
class Key {
String[] data;
Key(String... arg) {
data=arg;
}
public Key add(String next) {
int pos = data.length;
String[] newData=Arrays.copyOf(data, pos+1);
newData[pos]=next;
return new Key(newData);
}
#Override
public String toString() {
return "Key("+Arrays.toString(data)+')';
}
}
(assuming String as element type), we can use
final List<Key> keys =
firstElementCreator.getApplicableElements().stream().map(Key::new)
.flatMap(e -> secondElementCreator.getApplicableElements().stream().map(e::add))
.flatMap(e -> thirdElementCreator.getApplicableElements().stream().map(e::add))
// ... more creators
.collect(Collectors.toList());
Note that these flatMap steps are now on the same level, i.e. not nested anymore. Also, all these steps are identical, only differing in the actual creator, which leads to the general solution supporting an arbitrary number of Creator instances.
List<Key> keys = Stream.of(firstElementCreator, secondElementCreator, thirdElementCreator
/* , and, some, more, if you like */)
.map(creator -> (Function<Key,Stream<Key>>)
key -> creator.getApplicableElements().stream().map(key::add))
.reduce(Stream::of, (f1,f2) -> key -> f1.apply(key).flatMap(f2))
.apply(new Key())
.collect(Collectors.toList());
Here, every creator is mapping to the identical stream-producing function of the previous solution, then all are reduced to a single function combining each function with a flatMap step to the next one, and finally the resulting function is executed to get a stream, which is then collected to a List.
This is a two-part question. I'm just learning about predicates in Java 8 and I need to know if there is a predicate that I can pass to the filter() method to select the max in a list of integers, as below:
List<Integer> numbers = ...
Integer max = numbers.stream()
.filter(n -> ???)
.getFirst()
.get();
The bigger question is: can predicates be chained mathematically so that one doesn't have to chain filter() or reduce() methods, such that the work done in one predicate can be reflected in or passed to the following one, so instead of writing:
list.stream()
.filter(/* predicate1 */
item -> {
// do some work and save in some local variable "var"
})
.filter(/* predicate2 */ var -> ...)
.reduce(predicate3)
.getFirst()
.get();
I could write:
list.stream()
.filter(predicate1 "andThen" predicate2 "andThen" reduce by predicate3)
.getFirst()
.get();
I speculate that there might be a way using the andThen() functionality or writing a custom predicate. Can anyone help me understand this better?
No, you cannot use filter(Predicate) to select the maximum value of a Stream.
You have multiple other options:
stream.max(Comparator.naturalOrder());
stream.sorted(Comparator.reverseOrder()).findFirst();
stream.mapToInt(i -> i).max();
stream.reduce(Integer::max);
Yes, Predicates can be chained by and(Predicate). The implementation basically looks like this:
Predicate<T> and(Predicate<? super T> other) {
return t -> test(t) && other.test(t);
}
You could also simply write your own:
static <T> Predicate<T> and(Predicate<? super T>... ps) {
return t -> Stream.of(ps).allMatch(p -> p.test(t));
}
Usage:
stream.filter(and(i -> i > 11, i -> i < 50))
You can apply multiple filters, so you usually chain the calls:
stream.filter(i -> i > 11).filter(i -> i < 50)
Do you understand what reduce(BinaryOperator) does? You cannot put a Predicate in there.
I have already used it above as an option to get the maximum value.
I have the following expression:
scheduleIntervalContainers.stream()
.filter(sic -> ((ScheduleIntervalContainer) sic).getStartTime() != ((ScheduleIntervalContainer)sic).getEndTime())
.collect(Collectors.toList());
...where scheduleIntervalContainers has element type ScheduleContainer:
final List<ScheduleContainer> scheduleIntervalContainers
Is it possible to check the type before the filter?
You can apply another filter in order to keep only the ScheduleIntervalContainer instances, and adding a map will save you the later casts :
scheduleIntervalContainers.stream()
.filter(sc -> sc instanceof ScheduleIntervalContainer)
.map (sc -> (ScheduleIntervalContainer) sc)
.filter(sic -> sic.getStartTime() != sic.getEndTime())
.collect(Collectors.toList());
Or, as Holger commented, you can replace the lambda expressions with method references if you prefer that style:
scheduleIntervalContainers.stream()
.filter(ScheduleIntervalContainer.class::isInstance)
.map (ScheduleIntervalContainer.class::cast)
.filter(sic -> sic.getStartTime() != sic.getEndTime())
.collect(Collectors.toList());
A pretty elegant option is to use method reference of class:
scheduleIntervalContainers
.stream()
.filter( ScheduleIntervalContainer.class::isInstance )
.map( ScheduleIntervalContainer.class::cast )
.filter( sic -> sic.getStartTime() != sic.getEndTime())
.collect(Collectors.toList() );
There is a small problem with #Eran solution - typing class name in both filter and map is error-prone - it is easy to forget to change the name of the class in both places. An improved solution would be something like this:
private static <T, R> Function<T, Stream<R>> select(Class<R> clazz) {
return e -> clazz.isInstance(e) ? Stream.of(clazz.cast(e)) : null;
}
scheduleIntervalContainers
.stream()
.flatMap(select(ScheduleIntervalContainer.class))
.filter( sic -> sic.getStartTime() != sic.getEndTime())
.collect(Collectors.toList());
However there might be a performance penalty in creating a Stream for every matching element. Be careful to use it on huge data sets. I've learned this solution from #Tagir Vailev
Instead of a filter + map like other answers suggest, I would recommend this utility method:
public static <Super, Sub extends Super> Function<Super, Stream<Sub>> filterType(Class<Sub> clz) {
return obj -> clz.isInstance(obj) ? Stream.of(clz.cast(obj)) : Stream.empty();
}
Use it as:
Stream.of(dog, cat fish)
.flatMap(filterType(Dog.class));
Compared to filter + map it has the following advantages:
If the class does not extend your class you will get a compile error
Single place, you can never forget to change a class in either filter or map
Filter by class type with StreamEx
StreamEx.of(myCollection).select(TheThing.class).toList();
Given a list of elements, I want to get the element with a given property and remove it from the list. The best solution I found is:
ProducerDTO p = producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.get();
producersProcedureActive.remove(p);
Is it possible to combine get and remove in a lambda expression?
To Remove element from the list
objectA.removeIf(x -> conditions);
eg:
objectA.removeIf(x -> blockedWorkerIds.contains(x));
List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");
List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");
str1.removeIf(x -> str2.contains(x));
str1.forEach(System.out::println);
OUTPUT:
A
B
C
Although the thread is quite old, still thought to provide solution - using Java8.
Make the use of removeIf function. Time complexity is O(n)
producersProcedureActive.removeIf(producer -> producer.getPod().equals(pod));
API reference: removeIf docs
Assumption: producersProcedureActive is a List
NOTE: With this approach you won't be able to get the hold of the deleted item.
Consider using vanilla java iterators to perform the task:
public static <T> T findAndRemoveFirst(Iterable<? extends T> collection, Predicate<? super T> test) {
T value = null;
for (Iterator<? extends T> it = collection.iterator(); it.hasNext();)
if (test.test(value = it.next())) {
it.remove();
return value;
}
return null;
}
Advantages:
It is plain and obvious.
It traverses only once and only up to the matching element.
You can do it on any Iterable even without stream() support (at least those implementing remove() on their iterator).
Disadvantages:
You cannot do it in place as a single expression (auxiliary method or variable required)
As for the
Is it possible to combine get and remove in a lambda expression?
other answers clearly show that it is possible, but you should be aware of
Search and removal may traverse the list twice
ConcurrentModificationException may be thrown when removing element from the list being iterated
The direct solution would be to invoke ifPresent(consumer) on the Optional returned by findFirst(). This consumer will be invoked when the optional is not empty. The benefit also is that it won't throw an exception if the find operation returned an empty optional, like your current code would do; instead, nothing will happen.
If you want to return the removed value, you can map the Optional to the result of calling remove:
producersProcedureActive.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.map(p -> {
producersProcedureActive.remove(p);
return p;
});
But note that the remove(Object) operation will again traverse the list to find the element to remove. If you have a list with random access, like an ArrayList, it would be better to make a Stream over the indexes of the list and find the first index matching the predicate:
IntStream.range(0, producersProcedureActive.size())
.filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
.boxed()
.findFirst()
.map(i -> producersProcedureActive.remove((int) i));
With this solution, the remove(int) operation operates directly on the index.
Use can use filter of Java 8, and create another list if you don't want to change the old list:
List<ProducerDTO> result = producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.collect(Collectors.toList());
I'm sure this will be an unpopular answer, but it works...
ProducerDTO[] p = new ProducerDTO[1];
producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.ifPresent(producer -> {producersProcedureActive.remove(producer); p[0] = producer;}
p[0] will either hold the found element or be null.
The "trick" here is circumventing the "effectively final" problem by using an array reference that is effectively final, but setting its first element.
With Eclipse Collections you can use detectIndex along with remove(int) on any java.util.List.
List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = Iterate.detectIndex(integers, i -> i > 2);
if (index > -1) {
integers.remove(index);
}
Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);
If you use the MutableList type from Eclipse Collections, you can call the detectIndex method directly on the list.
MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = integers.detectIndex(i -> i > 2);
if (index > -1) {
integers.remove(index);
}
Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);
Note: I am a committer for Eclipse Collections
The below logic is the solution without modifying the original list
List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");
List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");
List<String> str3 = str1.stream()
.filter(item -> !str2.contains(item))
.collect(Collectors.toList());
str1 // ["A", "B", "C", "D"]
str2 // ["D", "E"]
str3 // ["A", "B", "C"]
When we want to get multiple elements from a List into a new list (filter using a predicate) and remove them from the existing list, I could not find a proper answer anywhere.
Here is how we can do it using Java Streaming API partitioning.
Map<Boolean, List<ProducerDTO>> classifiedElements = producersProcedureActive
.stream()
.collect(Collectors.partitioningBy(producer -> producer.getPod().equals(pod)));
// get two new lists
List<ProducerDTO> matching = classifiedElements.get(true);
List<ProducerDTO> nonMatching = classifiedElements.get(false);
// OR get non-matching elements to the existing list
producersProcedureActive = classifiedElements.get(false);
This way you effectively remove the filtered elements from the original list and add them to a new list.
Refer the 5.2. Collectors.partitioningBy section of this article.
As others have suggested, this might be a use case for loops and iterables. In my opinion, this is the simplest approach. If you want to modify the list in-place, it cannot be considered "real" functional programming anyway. But you could use Collectors.partitioningBy() in order to get a new list with elements which satisfy your condition, and a new list of those which don't. Of course with this approach, if you have multiple elements satisfying the condition, all of those will be in that list and not only the first.
the task is: get ✶and✶ remove element from list
p.stream().collect( Collectors.collectingAndThen( Collector.of(
ArrayDeque::new,
(a, producer) -> {
if( producer.getPod().equals( pod ) )
a.addLast( producer );
},
(a1, a2) -> {
return( a1 );
},
rslt -> rslt.pollFirst()
),
(e) -> {
if( e != null )
p.remove( e ); // remove
return( e ); // get
} ) );
resumoRemessaPorInstrucoes.removeIf(item ->
item.getTipoOcorrenciaRegistro() == TipoOcorrenciaRegistroRemessa.PEDIDO_PROTESTO.getNome() ||
item.getTipoOcorrenciaRegistro() == TipoOcorrenciaRegistroRemessa.SUSTAR_PROTESTO_BAIXAR_TITULO.getNome());
Combining my initial idea and your answers I reached what seems to be the solution
to my own question:
public ProducerDTO findAndRemove(String pod) {
ProducerDTO p = null;
try {
p = IntStream.range(0, producersProcedureActive.size())
.filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
.boxed()
.findFirst()
.map(i -> producersProcedureActive.remove((int)i))
.get();
logger.debug(p);
} catch (NoSuchElementException e) {
logger.error("No producer found with POD [" + pod + "]");
}
return p;
}
It lets remove the object using remove(int) that do not traverse again the
list (as suggested by #Tunaki) and it lets return the removed object to
the function caller.
I read your answers that suggest me to choose safe methods like ifPresent instead of get but I do not find a way to use them in this scenario.
Are there any important drawback in this kind of solution?
Edit following #Holger advice
This should be the function I needed
public ProducerDTO findAndRemove(String pod) {
return IntStream.range(0, producersProcedureActive.size())
.filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
.boxed()
.findFirst()
.map(i -> producersProcedureActive.remove((int)i))
.orElseGet(() -> {
logger.error("No producer found with POD [" + pod + "]");
return null;
});
}
A variation of the above:
import static java.util.function.Predicate.not;
final Optional<MyItem> myItem = originalCollection.stream().filter(myPredicate(someInfo)).findFirst();
final List<MyItem> myOtherItems = originalCollection.stream().filter(not(myPredicate(someInfo))).toList();
private Predicate<MyItem> myPredicate(Object someInfo) {
return myItem -> myItem.someField() == someInfo;
}