Skip and Take option for java arraylist? - java

I am very new to java, i know skip and take are very easy using linq in dot net. But i dont know how to achieve skip and take process in java for array list. any linq like option available in java?

Arnaud Denoyelle is correct; you want to use streams.
The Java 8 equivalents of .NET's .skip() and .take() are .skip() and .limit()

I looked at this link to understand what are "skip and take".
From Java 8, you can do such things with Streams. Stream.filter() enables you to define a Predicate which is your equivalent of take(). You can obtain skip by filtering on the opposite Predicate :
List<Integer> list = [...];
List<Integer> result = list.stream()
.filter(i -> i % 2 == 0) //Use any Predicate you want.
.collect(Collectors.toList()); //Convert the Stream back to a list

Related

Java stream map-if-or-else with predicate and alternative value

Do Java streams have a convenient way to map based upon a predicate, but if the predicate is not met to map to some other value?
Let's say I have Stream.of("2021", "", "2023"). I want to map that to Stream.of(Optional.of(Year.of(2021)), Optional.empty(), Optional.of(Year.of(2023))). Here's one way I could do that:
Stream<String> yearStrings = Stream.of("2021", "", "2023");
Stream<Optional<Year>> yearsFound = yearStrings.map(yearString ->
!yearString.isEmpty() ? Year.parse(yearString) : null)
.map(Optional::ofNullable);
But here is what I would like to do, using a hypothetical filter-map:
Stream<String> yearStrings = Stream.of("2021", "", "2023");
Stream<Optional<Year>> yearsFound = yearStrings.mapIfOrElse(not(String::isEmpty),
Year::parse, null).map(Optional::ofNullable);
Of course I can write my own mapIfOrElse(Predicate<>, Function<>, T) function to use with Stream.map(), but I wanted to check if there is something similar in Java's existing arsenal that I've missed.
There is not a very much better way of doing it than you have it - it might be nicer if you extracted it to a method, but that's really it.
Another way might be to construct Optionals from all values, and then use Optional.filter to map empty values to empty optionals:
yearStreams.map(Optional::of)
.map(opt -> opt.filter(Predicate.not(String::isEmpty)));
Is this better? Probably not.
Yet another way would be to make use of something like Guava's Strings.emptyToNull (other libraries are available), which turns your empty strings into null first; and then use Optional.ofNullable to turn non-nulls and nulls into non-empty and empty Optionals, respectively:
yearStreams.map(Strings::emptyToNull)
.map(Optional::ofNullable)
You can just simply use filter to validate and then only map
Stream<Year> yearsFound = yearStrings.filter(yearString->!yearString.isEmpty()).map(Year::parse)
It's hardly possible to combine all these actions smoothly in well-readable way within a single stream operation.
Here's a weird method-chaining with Java 16 mapMulti():
Stream<Optional<Year>> yearsFound = yearStrings
.mapMulti((yearString, consumer) ->
Optional.of(yearString).filter(s -> !s.isEmpty()).map(Year::parse)
.ifPresentOrElse(year -> consumer.accept(Optional.of(year)),
() -> consumer.accept(Optional.empty()))
);

In Java what would be the more efficient way than stream().forEach() but still using stream operation?

For example, I have a List of Strings (probably over 5000, and I need efficiency!). And I want to apply the same operation on each of them, e.g. splitting or others.
For now I use
List<String> a = ....;
a.stream().forEach(x->{
//some code here...
//maybe a split?
String[] ss=x.split("...");
Arrays.stream(ss).forEach(y->{...});
});
I know it is very unefficient for now, but how can I improve this? Btw parallelStream should not be used!
Edit:
I tried map operations e.g.
a.stream.map(x->x.split(...)).collect(Collectors.toList())
But it is for more less efficient than using forEach operation, although the code looks much cleaner.
Thank you very much for your help!
You can use the map function, to map the strings to a desired value, then iterate over them
a.stream().map(s -> s.split("...")).forEach(split -> {});
Or, you can filter them,
a.stream().map(s -> s.split("...")).filter(split -> split.length > 0);
Or you can collect them,
a.stream().map(s -> s.split("...")).filter(split -> split.length > 0).collect(Collectors.toList());
There are many things you can do with streams these are just some examples.

How to get index of findFirst() in java 8?

I have the following code:
ArrayList <String> entries = new ArrayList <String>();
entries.add("0");
entries.add("1");
entries.add("2");
entries.add("3");
String firstNotHiddenItem = entries.stream()
.filter(e -> e.equals("2"))
.findFirst()
.get();
I need to know what is the index of that first returned element, since I need to edit it inside of entries ArrayList. As far as I know get() returns the value of the element, not a reference. Should I just use
int indexOf(Object o)
instead?
You can get the index of an element using an IntStream like:
int index = IntStream.range(0, entries.size())
.filter(i -> "2".equals(entries.get(i)))
.findFirst().orElse(-1);
But you should use the List::indexOf method which is the preferred way, because it's more concise, more expressive and computes the same results.
You can't in a straightforward way - streams process elements without context of where they are in the stream.
However, if you're prepared to take the gloves off...
int[] position = {-1};
String firstNotHiddenItem = entries.stream()
.peek(x -> position[0]++) // increment every element encounter
.filter("2"::equals)
.findFirst()
.get();
System.out.println(position[0]); // 2
The use of an int[], instead of a simple int, is to circumvent the "effectively final" requirement; the reference to the array is constant, only its contents change.
Note also the use of a method reference "2"::equals instead of a lambda e -> e.equals("2"), which not only avoids a possible NPE (if a stream element is null) and more importantly looks way cooler.
A more palatable (less hackalicious) version:
AtomicInteger position = new AtomicInteger(-1);
String firstNotHiddenItem = entries.stream()
.peek(x -> position.incrementAndGet()) // increment every element encounter
.filter("2"::equals)
.findFirst()
.get();
position.get(); // 2
This will work using Eclipse Collections with Java 8
int firstIndex = ListIterate.detectIndex(entries, "2"::equals);
If you use a MutableList, you can simplify the code as follows:
MutableList<String> entries = Lists.mutable.with("0", "1", "2", "3");
int firstIndex = entries.detectIndex("2"::equals);
There is also a method to find the last index.
int lastIndex = entries.detectLastIndex("2"::equals);
Note: I am a committer for Eclipse Collections
Yes, you should use indexOf("2") instead. As you might have noticed, any stream based solution has a higher complexity, without providing any benefit.
In this specific situation, there is no significant difference in performance, but overusing streams can cause dramatic performance degradation, e.g. when using map.entrySet().stream().filter(e -> e.getKey().equals(object)).map(e -> e.getValue()) instead of a simple map.get(object).
The collection operations may utilize their known structure while most stream operation imply a linear search. So genuine collection operations are preferable.
Of course, if there is no collection operation, like when your predicate is not a simple equality test, the Stream API may be the right tool. As shown in “Is there a concise way to iterate over a stream with indices in Java 8?”, the solution for any task involving the indices works by using the indices as starting point, e.g. via IntStream.range, and accessing the list via List.get(int). If the source in not an array or a random access List, there is no equally clean and efficient solution. Sometimes, a loop might turn out to be the simplest and most efficient solution.

How to work with Java 8 streams?

I want to know how to work with Java 8 streams and how to use the different kind of available stream operations.
For example, I wrote this part of code:
ArrayList<State> toBeRemoved = new ArrayList<>();
for (State s : newStates)
if (path.contains(s)) // path is a stack of State
toBeRemoved.add(s);
for (State s : toBeRemoved)
newStates.remove(s);
I want to rewrite it using java 8 stream api calls. How can I do it?
No need for a stream here, you can use the new Collection#removeIf method:
newStates.removeIf(path::contains);
Or, if path is a Collection:
newStates.removeAll(path);
In this case, you can simply produce an output List containing only the States that should be retained, and assign that List to the newStates variable :
newStates = newStates.stream()
.filter(s -> !path.contains(s))
.collect(Collectors.toList());
The filter keeps only States for which path.contains(s) returns false.
Of course, if newStates is originally initialized as a copy of some "oldStates" List, you can skip that initilization step and use the original "oldStates" List as input.

How to print two lists together using Stream API java 8?

I have two lists as follow
List<String> names = Arrays.asList("James","John","Fred");
List<Integer> ages = Arrays.asList(25,35,15);
What i want to do is to print those two lists like so
James:25
John:35
Fred:15
It is easy to do it using the classic way
for(int i=0;i<names.size();i++){
System.out.println(names.get(i)+":"+ages.get(i));
}
Is there a way to do it using Stream API java 8?
What i am able to do is to print only one single list
names.stream().forEach(System.out::println);
The easiest way is to create an IntStream to generate the indices, and then map each index to the String you want to create.
IntStream.range(0, Math.min(names.size(), ages.size()))
.mapToObj(i -> names.get(i)+":"+ages.get(i))
.forEach(System.out::println);
Also you might be interested in this SO question Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip), because this is the kind of functionality you're asking for.
My StreamEx library has some syntactic sugar for this case:
StreamEx.zip(names, ages, (name, age) -> name+":"+age).forEach(System.out::println)
Basically inside it's the same as in accepted answer. The only difference is that IllegalArgumentException will be thrown if size of lists differs.
While Alexis C. answer is correct, one would argue it is the easiest way to achieve requested behavior in Java 8. I propose:
int[] i = {0};
names.forEach(name -> {
System.out.println(name + ages.get(i[0]++));
});
Or even without index:
List<Integer> agesCopy = new ArrayList<Integer>(ages);
names.forEach(name -> {
System.out.println(name + agesCopy.remove(0));
});

Categories