analyticsDatabases is of type -
private final Iterable<Database> analyticsDatabases;
And I use below code snippet inside a method, and I have one element in analyticsDatabases List. When I do a for loop all works fine, but I am curious why my Iterables.transform doesn't work.
Iterable<Iterable<ObjectId>> finalR = Iterables.transform(analyticsDatabases, new Function<Database, Iterable<ObjectId>>() {
#Nullable
#Override
public Iterable<ObjectId> apply(#Nullable Database database) {
if (database != null) {
return database.deleteItemsById(filterIds, storableType, writeAckStrategy);
}
`enter code here`
return null;
}
});
The javadoc of Iterables states
Performance notes: Unless otherwise noted, all of the iterables
produced in this class are lazy, which means that their iterators only
advance the backing iteration when absolutely necessary.
In other words, transform doesn't apply the given Function. It returns an Iterable that will apply the Function as elements are requested.
Related
I couldn't wrap my head around writing the below condition using Java Streams. Let's assume that I have a list of elements from the periodic table. I've to write a method that returns a String by checking whether the list has Silicon or Radium or Both. If it has only Silicon, method has to return Silicon. If it has only Radium, method has to return Radium. If it has both, method has to return Both. If none of them are available, method returns "" (default value).
Currently, the code that I've written is below.
String resolve(List<Element> elements) {
AtomicReference<String> value = new AtomicReference<>("");
elements.stream()
.map(Element::getName)
.forEach(name -> {
if (name.equalsIgnoreCase("RADIUM")) {
if (value.get().equals("")) {
value.set("RADIUM");
} else {
value.set("BOTH");
}
} else if (name.equalsIgnoreCase("SILICON")) {
if (value.get().equals("")) {
value.set("SILICON");
} else {
value.set("BOTH");
}
}
});
return value.get();
}
I understand the code looks messier and looks more imperative than functional. But I don't know how to write it in a better manner using streams. I've also considered the possibility of going through the list couple of times to filter elements Silicon and Radium and finalizing based on that. But it doesn't seem efficient going through a list twice.
NOTE : I also understand that this could be written in an imperative manner rather than complicating with streams and atomic variables. I just want to know how to write the same logic using streams.
Please share your suggestions on better ways to achieve the same goal using Java Streams.
It could be done with Stream IPA in a single statement and without multiline lambdas, nested conditions and impure function that changes the state outside the lambda.
My approach is to introduce an enum which elements correspond to all possible outcomes with its constants EMPTY, SILICON, RADIUM, BOTH.
All the return values apart from empty string can be obtained by invoking the method name() derived from the java.lang.Enum. And only to caver the case with empty string, I've added getName() method.
Note that since Java 16 enums can be declared locally inside a method.
The logic of the stream pipeline is the following:
stream elements turns into a stream of string;
gets filtered and transformed into a stream of enum constants;
reduction is done on the enum members;
optional of enum turs into an optional of string.
Implementation can look like this:
public static String resolve(List<Element> elements) {
return elements.stream()
.map(Element::getName)
.map(String::toUpperCase)
.filter(str -> str.equals("SILICON") || str.equals("RADIUM"))
.map(Elements::valueOf)
.reduce((result, next) -> result == Elements.BOTH || result != next ? Elements.BOTH : next)
.map(Elements::getName)
.orElse("");
}
enum
enum Elements {EMPTY, SILICON, RADIUM, BOTH;
String getName() {
return this == EMPTY ? "" : name(); // note name() declared in the java.lang.Enum as final and can't be overridden
}
}
main
public static void main(String[] args) {
System.out.println(resolve(List.of(new Element("Silicon"), new Element("Lithium"))));
System.out.println(resolve(List.of(new Element("Silicon"), new Element("Radium"))));
System.out.println(resolve(List.of(new Element("Ferrum"), new Element("Oxygen"), new Element("Aurum")))
.isEmpty() + " - no target elements"); // output is an empty string
}
output
SILICON
BOTH
true - no target elements
Note:
Although with streams you can produce the result in O(n) time iterative approach might be better for this task. Think about it this way: if you have a list of 10.000 elements in the list and it starts with "SILICON" and "RADIUM". You could easily break the loop and return "BOTH".
Stateful operations in the streams has to be avoided according to the documentation, also to understand why javadoc warns against stateful streams you might take a look at this question. If you want to play around with AtomicReference it's totally fine, just keep in mind that this approach is not considered to be good practice.
I guess if I had implemented such a method with streams, the overall logic would be the same as above, but without utilizing an enum. Since only a single object is needed it's a reduction, so I'll apply reduce() on a stream of strings, extract the reduction logic with all the conditions to a separate method. Normally, lambdas have to be well-readable one-liners.
Collect the strings to a unique set. Then check containment in constant time.
Set<String> names = elements.stream().map(Element::getName).map(String::toLowerCase).collect(toSet());
boolean hasSilicon = names.contains("silicon");
boolean hasRadium = names.contains("radium");
String result = "";
if (hasSilicon && hasRadium) {
result = "BOTH";
} else if (hasSilicon) {
result = "SILICON";
} else if (hasRadium) {
result = "RADIUM";
}
return result;
i have used predicate in filter to for radium and silicon and using the resulted set i am printing the result.
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
List<Element> elementss = new ArrayList<>();
Set<String> stringSet = elementss.stream().map(e -> e.getName())
.filter(string -> (string.equals("Radium") || string.equals("Silicon")))
.collect(Collectors.toSet());
if(stringSet.size()==2){
System.out.println("both");
}else if(stringSet.size()==1){
System.out.println(stringSet);
}else{
System.out.println(" ");
}
}
}
You could save a few lines if you use regex, but I doubt if it is better than the other answers:
String resolve(List<Element> elements) {
String result = elements.stream()
.map(Element::getName)
.map(String::toUpperCase)
.filter(str -> str.matches("RADIUM|SILICON"))
.sorted()
.collect(Collectors.joining());
return result.matches("RADIUMSILICON") ? "BOTH" : result;
}
I need to implement function that returns Mono< Array< ProcessedObject>>. As argument it takes list of objects and process them with function that returns Mono< ProcessedObject>. Function needs to keep original order, meaning first element on returned list must be created from first element from argument list. So far i have following solution but it doesn't keep required order. Is it even possible with Flux?
private fun createItems(objects: List<Someobjects>): Mono<Array<ProcessedObject>> {
return Flux.fromIterable(objects)
.flatMap {
processObject(it)
}.collectList().map { it.toTypedArray() }
}
Edit: to clarify a little processObject returns Mono< ProcessedObject>
You can try with concatMap instead of flatMap.
Here is a link for the Docu https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#concatMap-java.util.function.Function-
private fun createItems(objects: List<Someobjects>): Mono<Array<ProcessedObject> {
return Flux.fromIterable(objects)
.concatMap {
processObject(it)
}.collectList().map { it.toTypedArray() }
}
The difference between flatMap and concatMap is that the later preserves the original order.
The idea of LinkedList is, that each element has a reference to its successor (and predecessor in the case of doubled linked list), so concatenation of two LinkedLists happens that last element of the first list get reference to first element of second list Detailed explanation here, what is made in O(1) time.
Howewer they made it stupid in Java.
It has no method java.util.LinkedList.addFirst(LinkedList) or something.
if you look at the method java.util.LinkedList.addAll(Collection), it iterates over an array, what collection returns with c.toArray(), and then adds each element of this array. What is even twice stupid:
1) linked list is iterated in 0(n)
2) elements are added to linked list in 0(n) time.
Is there any possibility to extends the standart LinkedList so he would have good concatenation method? Because now, the simplest, but bad solution i see to make the copy- paste of LinkedList code and make some methods protected in order to extend that with implementation of right addALL
You can't use addAll for that, because O(1) linked list concatenation is a destructive operation. In other words, you start with two non-empty lists, and end up with one big list and one empty list.
You are looking for two operations
void transferBeforeFirst(LinkedList<T> other);
void transferAfterLast(LinkedList<T> other);
They take LinkedList<T> other in whatever state it may be, and leave it empty upon return. This is rather counterintuitive, because generally the caller expects to find his data unchanged after calling a library method.
Of course, technically this could certainly be done. However, this goes against the grain of Java API design, which prefers to leave method parameters unchanged.
I don't think there is a way to do that, and the reason is that java has a strong object orientation and doesn't operate with data in a direct way such has C does, so if you have two linked lists and you want to make one out of two, you are forced to copy one of them entirely instead of only liking it at the end of the other one.
This behaviour is because special casing the adding of two linked lists together would destroy the sconfd list.
Notice that the LinkedList.Node class has both a next and a prev so it is indeed doubly-linked. To just join the chains together would make list2.first.prev point to list1.last which would then break list2.
public void addLast(LinkedList<? extends E> l) {
// My list continues on into the new list.
last.next = l.first;
// Back-link too - THIS BREAKS l!!
l.first.prev = last;
// End of new list is now last.
last = l.last;
}
Secondly notice that LinkedList<? extends E>. Remember that you can extend LinkedList so you may be adding two lists of a completely different class together - that would also require careful handling.
If you really want to achieve O(1) you could write an IterableIterable that would walk an Itearble<Iterable<T>> delivering each element from each Iterable in turn - kind of like a flatMap for Iterables.
class IterableIterable<T> implements Iterable<T> {
private final Iterable<? extends Iterable<T>> i;
public IterableIterable(Iterable<? extends Iterable<T>> i) {
this.i = i;
}
#Override
public Iterator<T> iterator() {
return new IIT();
}
private class IIT implements Iterator<T> {
// Pull an iterator.
final Iterator<? extends Iterable<T>> iit = i.iterator();
// The current Iterator<T>
Iterator<T> it = null;
// The current T.
T next = null;
#Override
public boolean hasNext() {
boolean finished = false;
while (next == null && !finished) {
if (it == null || !it.hasNext()) {
if (iit.hasNext()) {
it = iit.next().iterator();
} else {
// All over when we've exhausted the list of lists.
finished = true;
}
}
if (it != null && it.hasNext()) {
// Get another from the current list.
next = it.next();
}
}
return next != null;
}
#Override
public T next() {
T n = next;
next = null;
return n;
}
}
}
That's why LinkedList has the addLast() method
https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#addLast%28E%29
and it does have a addFirst() too
https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#addFirst%28E%29
you can't do better than that, because Java has not the pointer concept.
you could try to implement your own native code for that, however.
I have the following code:
class Action {
public void step(Game game) {
//if some condition met,
// then remove self from action stack
game.actionStack.remove(this);
}
class Game (
public ArrayList<Action> actionStack;
public Game() {
actionStack = new Arraylist<Action>();
actionStack.add(new Action());
while (true) {
for (Action action : this.actionStack) {
action.step(this);
}
}
}
}
An exception gets thrown when game.actionStack.remove(this); occurs. Is there a way to remove the element safely from inside the Action class like I want?
I'm guessing you're getting a ConcurrentModificationException because you're calling the list remove method while iterating it. You can't do that.
An easy fix is to work on a copy of the array when iterating:
for (Action action : new ArrayList<>(this.actionStack)) {
action.step(this);
}
A slightly more efficient fix is to use an explicit Iterator and call its remove method. Perhaps have step() return a boolean indicating whether it wants to remain in the list for the next step or not:
for (Iterator<Action> it = this.actionStack.iterator(); it.hasNext();) {
Action action = it.next();
if (!action.step(this)) {
it.remove();
}
}
From : the java tutorial we get the following:
Iterators
...
Note that Iterator.remove is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Use Iterator instead of the for-each construct when you need to:
Remove the current element. The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.
Iterate over multiple collections in parallel.
The following method shows you how to use an Iterator to filter an arbitrary Collection — that is, traverse the collection removing specific elements.
static void filter(Collection<?> c) {
for (Iterator<?> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
This simple piece of code is polymorphic, which means that it works for any Collection regardless of implementation. This example demonstrates how easy it is to write a polymorphic algorithm using the Java Collections Framework.
Note: I assume, you implemented equals and hashCode methods for your class
You need to use iterator to remove like below;
class Game (
public ArrayList<Action> actionStack;
public Game() {
actionStack = new Arraylist<Action>();
actionStack.add(new Action());
while (true) {
for (Iterator<Action> it = this.actionStack.iterator(); it.hasNext(); ) {
it.remove();
}
}
}
}
Edit: step function is doing simple remove job. I move it to Game constructor
I suspect that you are getting a Concurrent Modification Exception. I would suggest you do it like this
class Action {
public void step(Game game) {
//if some condition met,
// then remove self from action stack
List<Action> tmpActionList = new List<Action>();
tmpActionList = game.actionStack
tmpActionList.remove(this);
game.actionStack = tmpActionList;
}
}
Let me know if it works.
Say I have already created an iterator called "iter" and an arraylist called "database". I want to be able to look through the arraylist and see if any element in the arraylist is equal to a String called "test". If it is, then I would like to add the element to another list.
while(iter.hasNext()) {
if(database.next() == test) {
database.next().add(another_list);
}
}
What am I doing wrong? I'm completely new to iterators in java. Do I need to write my own iterator class? Any code examples would be greatly appreciated. Thanks
The problem with your code is that every time you call .next(), it advances the iterator forward to the next position. This means that this code
if(database.next() == test) {
database.next().add(another_list);
}
Won't work as intended, because the first call to database.next() will not give back the same value as the second call to database.next(). To fix this, you'll want to make a temporary variable to hold on to the new value, as seen here:
while(iter.hasNext()) {
/* type */ curr = iter.next();
if(curr == test) {
curr.add(another_list);
}
}
(Filling in the real type of what's being iterated over in place of /* type */)
In many cases, though, you don't need to use iterators explicitly. Most of the Collections types implement the Iterable interface, in which case you can just write
/* container */ c;
for(/* type */ curr: c) {
if(curr == test) {
curr.add(another_list);
}
}
Hope this helps!
if(database.contains("test"))
{
another_list.add("test");
}
you can use the built in method contains(...)
you should use equals(...) for data comparisions
look at the javadoc to see if there is already a method present for your purpose