I want to write a stream method that may need to ignore several concurrent values based on a "lastGoodVersion" but I can't find a way to share the value within the stream. Below is what I'd LIKE to do. Any suggestions on how to accomplish something like this?
[EDIT don't do this, it's not how java streams work]
I don't think this is possible using only Java 8 Streams. A possible solution to what you want to do could however use a helper function which may look something like this:
private static <T> Stream<T> progressiveFilter(Stream<T> stream,
BiPredicate<T, T> predicate) {
List<T> list = stream.collect(Collectors.toList());
List<T> result = new ArrayList<>();
T previousValue = null;
for (T entry : list) {
if (previousValue == null) {
previousValue = entry;
} else {
if (predicate.test(entry, previousValue)) {
result.add(previousValue);
} else {
previousValue = entry;
}
}
}
if(previousValue != null) {
result.add(previousValue);
}
return result.stream();
}
The call you are trying would then look something like this:
progressiveFilter(
allVersionsStream().filter(NSTimestamp::isApproved),
(v, lastCanonicalVersion) -> !v.isEffectiveBefore(relativeDate)
&& v.isEffectiveBefore(lastCanonicalVersion));
Quite possibly this can be further optimized. But the principle, I hope, is clear.
Obviously, you won't be able to modify a local variable from lambda body. You need a wrapper of some kind that contains the thing you want to modify. An array is often used for that purpose
VERSION[] lastCanonicalVersion = {null}
....
if(...lastCanonicalVersion[0]...)
lastCanonicalVersion[0] = v;
Related
I want to use Java 8 lambdas and streams to reduce the amount of code in the following method that produces an Optional. Is it possible to achieve?
My code:
protected Optional<String> getMediaName(Participant participant) {
for (ParticipantDevice device : participant.getDevices()) {
if (device.getMedia() != null && StringUtils.isNotEmpty(device.getMedia().getMediaType())) {
String mediaType = device.getMedia().getMediaType().toUpperCase();
Map<String, String> mediaToNameMap = config.getMediaMap();
if (mediaMap.containsKey(mediaType)) {
return Optional.of(mediaMap.get(mediaType));
}
}
}
return Optional.empty();
}
Yes. Assuming the following class hierarchy (I used records here).
record Media(String getMediaType) {
}
record ParticipantDevice(Media getMedia) {
}
record Participant(List<ParticipantDevice> getDevices) {
}
It is pretty self explanatory. Unless you have an empty string as a key you don't need, imo, to check for it in your search. The main difference here is that once the map entry is found, Optional.map is used to return the value instead of the key.
I also checked this out against your loop version and it works the same.
public static Optional<String> getMediaName(Participant participant) {
Map<String, String> mediaToNameMap = config.getMediaMap();
return participant.getDevices().stream()
.map(ParticipantDevice::getMedia).filter(Objects::nonNull)
.map(media -> media.getMediaType().toUpperCase())
.filter(mediaType -> mediaToNameMap.containsKey(mediaType))
.findFirst()
.map(mediaToNameMap::get);
}
Firstly, since your Map of media types returned by config.getMediaMap() doesn't depend on a particular device, it makes sense to generate it before processing the collection of devices. I.e. regurless of the approach (imperative or declarative) do it outside a Loop, or before creating a Stream, to avoid generating the same Map multiple times.
And to implement this method with Streams, you need to use filter() operation, which expects a Predicate, to apply the conditional logic and map() perform a transformation of stream elements.
To get the first element that matches the conditions apply findFirst(), which produces an optional result, as a terminal operation.
protected Optional<String> getMediaName(Participant participant) {
Map<String, String> mediaToNameMap = config.getMediaMap();
return participant.getDevices().stream()
.filter(device -> device.getMedia() != null
&& StringUtils.isNotEmpty(device.getMedia().getMediaType())
)
.map(device -> device.getMedia().getMediaType().toUpperCase())
.filter(mediaToNameMap::containsKey)
.map(mediaToNameMap::get)
.findFirst();
}
I have a function:
String fun(List<Function<String, String>> pro, String x){
for(var p: pro){
x = p.apply(x);
}
return x;
}
How can I convert this function to functional style instead of imperative style?
Assuming what you want is to apply each function to your string, passing along the result of each function to the next, you can do this with reduce.
String fun(List<Function<String, String>> functions, String x) {
return functions.stream()
.reduce(s -> s, Function::andThen)
.apply(x);
}
Using reduce with andThen creates a combined function that chains your list of functions together. We then apply the combined function to x.
Alternatively, #Naman in the comments suggests the formulation:
functions.stream()
.reduce(Function::andThen)
.orElse(Function.identity())
.apply(x)
which I believe performs one fewer andThen operation (when the list of functions is nonempty), but is functionally the same as the first version.
(Function.identity() is an another way to write s -> s.)
I believe you are already aware about those compilation errors. You can't just define List<Function<>> without having a common understanding about those list of functions. Maybe you can get some inspiration from below code snippet.
String fun(List<Function<String, String>> listOfFunctions, String commonInputStr){
for (Function<String, String> function : listOfFunctions) {
String tempValStr = function.apply(commonInputStr);
if (tempValStr != null){
return tempValStr;
}
}
return null;
}
Or if you want to find the first result value like below:
Optional<String> fun(List<Function<String, String>> listOfFunctions, String commonInputStr){
return listOfFunctions.stream()
.map(stringStringFunction -> stringStringFunction.apply(commonInputStr))
.findFirst();
}
I'm implementing graph representation.
Map<V, List<E<V>>> g = new HashMap<>();
one of methods in Graph class is
List<E<V>> getAllEdges() {
List<E<V>> allEdges = new ArrayList<>();
for(Map.Entry<V, List<E<V>>> entry: g.entrySet()) {
allEdges.addAll(entry.getValue());
}
return allEdges;
}
But I'd like to make it shorter line using
List<E<V>> getAllEdges() {
return g.values().stream().collect(Collectors.toList());
}
but I have an error such that
Is there a way to use stream for this?
Since your values are already typed as List<E<V>, using .collect(Collectors.toList()) is appropriate if you want to build a List<List<E<V>>.
To fix it, flatten the 2D list using flatMap:
List<E<V>> getAllEdges() {
return g.values().stream().flatMap(List::stream).collect(Collectors.toList());
}
I have a question about simplifying some Collection handling code, when using Google Collections (update: Guava).
I've got a bunch of "Computer" objects, and I want to end up with a Collection of their "resource id"s. This is done like so:
Collection<Computer> matchingComputers = findComputers();
Collection<String> resourceIds =
Lists.newArrayList(Iterables.transform(matchingComputers, new Function<Computer, String>() {
public String apply(Computer from) {
return from.getResourceId();
}
}));
Now, getResourceId() may return null (and changing that is not an option right now), yet in this case I'd like to omit nulls from the resulting String collection.
Here's one way to filter nulls out:
Collections2.filter(resourceIds, new Predicate<String>() {
#Override
public boolean apply(String input) {
return input != null;
}
});
You could put all that together like this:
Collection<String> resourceIds = Collections2.filter(
Lists.newArrayList(Iterables.transform(matchingComputers, new Function<Computer, String>() {
public String apply(Computer from) {
return from.getResourceId();
}
})), new Predicate<String>() {
#Override
public boolean apply(String input) {
return input != null;
}
});
But this is hardly elegant, let alone readable, for such a simple task! In fact, plain old Java code (with no fancy Predicate or Function stuff at all) would arguably be much cleaner:
Collection<String> resourceIds = Lists.newArrayList();
for (Computer computer : matchingComputers) {
String resourceId = computer.getResourceId();
if (resourceId != null) {
resourceIds.add(resourceId);
}
}
Using the above is certainly also an option, but out of curiosity (and desire to learn more of Google Collections), can you do the exact same thing in some shorter or more elegant way using Google Collections?
There's already a predicate in Predicates that will help you here -- Predicates.notNull() -- and you can use Iterables.filter() and the fact that Lists.newArrayList() can take an Iterable to clean this up a little more.
Collection<String> resourceIds = Lists.newArrayList(
Iterables.filter(
Iterables.transform(matchingComputers, yourFunction),
Predicates.notNull()
)
);
If you don't actually need a Collection, just an Iterable, then the Lists.newArrayList() call can go away too and you're one step cleaner again!
I suspect you might find that the Function will come in handy again, and will be most useful declared as
public class Computer {
// ...
public static Function<Computer, String> TO_ID = ...;
}
which cleans this up even more (and will promote reuse).
A bit "prettier" syntax with FluentIterable (since Guava 12):
ImmutableList<String> resourceIds = FluentIterable.from(matchingComputers)
.transform(getResourceId)
.filter(Predicates.notNull())
.toList();
static final Function<Computer, String> getResourceId =
new Function<Computer, String>() {
#Override
public String apply(Computer computer) {
return computer.getResourceId();
}
};
Note that the returned list is an ImmutableList. However, you can use copyInto() method to pour the elements into an arbitrary collection.
It took longer than #Jon Skeet expected, but Java 8 streams do make this simple:
List<String> resourceIds = computers.stream()
.map(Computer::getResourceId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
You can also use .filter(x -> x != null) if you like; the difference is very minor.
Firstly, I'd create a constant filter somewhere:
public static final Predicate<Object> NULL_FILTER = new Predicate<Object>() {
#Override
public boolean apply(Object input) {
return input != null;
}
}
Then you can use:
Iterable<String> ids = Iterables.transform(matchingComputers,
new Function<Computer, String>() {
public String apply(Computer from) {
return from.getResourceId();
}
}));
Collection<String> resourceIds = Lists.newArrayList(
Iterables.filter(ids, NULL_FILTER));
You can use the same null filter everywhere in your code.
If you use the same computing function elsewhere, you can make that a constant too, leaving just:
Collection<String> resourceIds = Lists.newArrayList(
Iterables.filter(
Iterables.transform(matchingComputers, RESOURCE_ID_PROJECTION),
NULL_FILTER));
It's certainly not as nice as the C# equivalent would be, but this is all going to get a lot nicer in Java 7 with closures and extension methods :)
You could write your own method like so. this will filter out nulls for any Function that returns null from the apply method.
public static <F, T> Collection<T> transformAndFilterNulls(List<F> fromList, Function<? super F, ? extends T> function) {
return Collections2.filter(Lists.transform(fromList, function), Predicates.<T>notNull());
}
The method can then be called with the following code.
Collection c = transformAndFilterNulls(Lists.newArrayList("", "SD", "DDF"), new Function<String, Long>() {
#Override
public Long apply(String s) {
return s.isEmpty() ? 20L : null;
}
});
System.err.println(c);
I was just wondering what the easiest way to iterate over a set indefinitely, i.e. when it reaches the end it next(); calls the first object. I'm assuming that this is not an already predefined function in Java, so just looking for the easiest way to implement this in Java.
There's a method in the excellent Google Collections library which does this:
Set<String> names = ...;
Iterable<String> infinite = Iterables.cycle(names);
(I can't recommend the Google Collections library strongly enough. It rocks very hard. I'm biased as I work for Google, but I think pretty much every Googler writing Java would tell you how useful the collections are.)
Iterator it = mylist.iterator();
while (it.hasNext())
{
MyType t = (MyType)it.next();
// do something
if (!it.hasNext())
it = mylist.iterator();
}
Try EndlessIterator from Cactoos:
Iterator<String> names = new EndlessIterator<>("John");
It will always return "John" and will never end.
Also, check EndlessIterable, which implements Iterable and does the same.
If you're making the iterator, in the next method you can have an if condition that checks if there's another object in the list. If there is, then you return that object, if there isn't then you go back to the start of the list and return that object.
This is what I can think of...
iterator = set.getIterator
//other code
if (iterator.hasNext())
//do code here
else
iterator = set.getIterator();
How about ?
List<String> list = // ArraysList
Interator<String> it = null;
while(true) {
it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
If you don't want to use Guava but still want a reusable solution:
public static class CyclicIterator<E, C extends Collection<E>> implements Iterator<E> {
final private C mElements;
private Iterator<E> mIterator;
public CyclicIterator(C elements) {
mElements = elements;
mIterator = elements.iterator();
}
#Override
public boolean hasNext() {
if (! mIterator.hasNext()) {
mIterator = mElements.iterator();
}
return mIterator.hasNext();
}
#Override
public E next() {
if (! mIterator.hasNext()) {
mIterator = mElements.iterator();
}
return mIterator.next();
}
}
Note: this doesn't support the remove() method but it could easily be added if needed. Also it's not thread safe.
I think what you want never help You can do anything with your iterator that's easy but you must be carefull with any new thing you add im not used with this style but this is what you want though :
if (! It.hasNext() )
{
while ( It.hasPrevious() )
{
It = It.Previous();
}
} else {
It = It.Next();
}
This way is nothing if your really interested you should instead make next pointer of the last to the first always when pushing a new list.
std jdk:
Iterable<String> infinite = Stream.generate(names.stream()).flatMap(e -> e).iterator()