I have a for loop structure like this:
for(T element1 : list1) {
for(T element2 : element1.getSubElements()) {
...
}
}
list1 contains about 10.000 elements and element1.getSubElements() also contains around 10-20 elements for each iteration.
The loop takes around 2 minutes to finish.
Any ideas about how to improve this?
The looping doesn't take that long. The work you do in the loop takes the time.
Your options are;
use a profiler to optimise the work inside the loop.
use parallelStream() to see if doing the work across multiple threads improves the time it takes.
I have an if, if the condition is true I add the element2 to an ArrayList. Maybe the problem is in the if?
To use parallelStream you can do
List<T> list2 = list1.parallelStream()
.flatMap(e -> e.getSubElements().stream())
.filter(e -> e.isConditionTrue())
.collect(Collectors.toList());
Try Lambda expression
list1.forEach(new T<E>() {
public void accept(E value) {
System.out.println(value);
}
});
Actually both the forEach method and the Consumer interface have been added in Java 8, but you can already do something very similar in Java 5+ using libraries like guava or lambdaj . However Java 8 lambda expressions allow to achieve the same result in a less verbose and more readable way:
list1.forEach((E value) -> System.out.println(value));
Related
Say I got 100 records from DB, I want to loop 10 times and perform some action.
and loop again and perform some action.. it continues until the last record is read.
The problem what i am seeing is
for (int number: numbers) {
add(number);
//after adding 10 items I want to complete a function and continue the loop
}
But here in Java, if use the above loop we can see it will iterate the complete list and comes out.
I know in older versions, we can iterate by counter like
for(int i=0; i<10;i++)
some thing like this.
My question is if forEach loop doesnot provide this flexibility, then why Sun Java introduced to a looping mechanism where it will iterate completely.
Trying to understand the logic of this design.
You can use a forEach or for-in with a nested conditional.
for(number: numbers){
if(number != (multOfTen)){
myFunction(number);
add(number);
}else{
add(number);
}
}
you will need to replace multOfTen w/ an expression that includes only multiples of ten.
One way to do this is to use regEx to check that the last digit is zero (so long as your using integers.)
As the name suggests, forEach will iterate over the whole collection. This is the same for JavaScript and several other languages. However you can abort / skip the iteration with a condition (which depends on the language implementation details).
There are difference between for and forEach loop. There are reason why java has these 2. forEach is enhance for loop. Both have their usage based on requirements.
for
This we can use for general purpose. This is totally based on indexes. If you want to play with data at particular index or want to perform some actions based on index of element, you should use for.
forEach
this is used with only collections and arrays. This iterate over whole collections at once. Means you can't have index of element while iterating it. This is used when you manipulate each data in list regardless whats its index. For example to print all element in a given list, instead of writing classical for loop
for (int i =0; i < list.length(); i++){
System.out.println(list(i));
}
we use forEach loop
list.forEach(e -> {
System.out.println(e);
});
this is more readable, easy to use and crisp.
because sometimes the question or the implementation you're doing using java doesn't need the index of the array "simply".
so instead of writing the whole for(int i=0;i<arr.length;i++) thing you can just use foreach and instead of arr[i] you use a simple variable name.
This is actually possible using the same Stream api but it's beyond the scope of forEach. What you want to do isn't possible by limiting yourself to forEach. The purpose of forEach is to execute some action without bias on all elements of an Iterable or Stream. What you can do is break down your objects into groups of 10 and then for each grouping of 10, do what you want which is add all to the underlying collection and then perform some other action which is what you want as well.
List<Integer> values = IntStream.range(0, 100)
.boxed()
.collect(Collectors.toList());
int batch = 10;
List<List<Integer>> groupsOfTen = IntStream.range(0, values.size() / batch + 1)
.map(index -> index * batch)
.mapToObj(index -> values.subList(index,
Math.min(index + batch, values.size())))
.collect(Collectors.toList());
groupsOfTen.forEach(myListOfTen -> myListOfTen.forEach(individual -> {
}));
I'm pretty new to java streams and am trying to determine how to find the max from each list, in a list of lists, and end with a single list that contains the max from each sublist.
I can accomplish this by using a for loop and stream like so:
// databaseRecordsLists is a List<List<DatabaseRecord>>
List<DatabaseRecord> mostRecentRecords = new ArrayList<>();
for (List<DatabaseRecord> databaseRecords : databaseRecordsLists) {
mostRecentRecords.add(databaseRecords.stream()
.max(Comparator.comparing(DatabaseRecord::getTimestamp))
.orElseThrow(NoSuchElementException::new));
}
I've looked into the flatMap api, but then I'll only end up with a single map of all DatabaseRecord objects, where I need a max from each individual list.
Any ideas on a cleaner way to accomplish this?
You don't need flatMap. Create a Stream<List<DatabaseRecord>>, and map each List<DatabaseRecord> of the Stream to the max element. Then collect all the max elements into the output List.
List<DatabaseRecord> mostRecentRecords =
databaseRecordsLists.stream()
.map(list -> list.stream()
.max(Comparator.comparing(DatabaseRecord::getTimestamp))
.orElseThrow(NoSuchElementException::new))
.collect(Collectors.toList());
Based on the comments, I suggested to rather ignore the empty collection, otherwise, no result would be returned and NoSuchElementException thrown even the empty collection might (?) be a valid state. If so, you can improve the current solution:
databaseRecordsLists.stream()
.filter(list -> !list.isEmpty()) // Only non-empty ones
.map(list -> list.stream()
.max(Comparator.comparing(DatabaseRecord::getTimestamp)) // Get these with max
.orElseThrow(NoSuchElementException::new)) // Never happens
.collect(Collectors.toList()); // To List
If you use a version higher than Java 8:
As of Java 10, orElseThrow(NoSuchElementException::new) can be subsituted with orElseThrow().
As of Java 11, you can use Predicate.not(..), therefore the filter part would look like: .filter(Predicate.not(List::isEmpty)).
I'm practicing streams in java 8 and im trying to make a Stream<Integer> containing the multiples of 2. There are several tasks in one main class so I won't link the whole block but what i got so far is this:
Integer twoToTheZeroth = 1;
UnaryOperator<Integer> doubler = (Integer x) -> 2 * x;
Stream<Integer> result = ?;
My question here probably isn't related strongly to the streams, more like the syntax, that how should I use the doubler to get the result?
Thanks in advance!
You can use Stream.iterate.
Stream<Integer> result = Stream.iterate(twoToTheZeroth, doubler);
or using the lambda directly
Stream.iterate(1, x -> 2*x);
The first argument is the "seed" (ie first element of the stream), the operator gets applied consecutively with every element access.
EDIT:
As Vinay points out, this will result in the stream being filled with 0s eventually (this is due to int overflow). To prevent that, maybe use BigInteger:
Stream.iterate(BigInteger.ONE,
x -> x.multiply(BigInteger.valueOf(2)))
.forEach(System.out::println);
Arrays.asList(1,2,3,4,5).stream().map(x -> x * x).forEach(x -> System.out.println(x));
so you can use the doubler in the map caller
I am seeking for an option to filter in-streams but using priorities.
The following is the pseudo code:
results.stream().filter(prio1).ifNotFound(filter(prio2)).collect(toList())
The list of results shall be filtered by first criteria called "prio1" and if there ain't no match found the second filter shall be applied to try filter on second criteria called prio2 and then the results shall be collected
How do I achive this in Java 8 using streams?
I am looking for a one-liner in stream.
You will need to stream() your results twice, but the following should work as a one-liner:
results.stream().filter(results.stream().anyMatch(prio1) ? prio1 : prio2).collect(Collectors.toList());
(Credit to flakes for first publishing a multiple-liner using a similar strategy.)
Edit: Since some excellent new answers have come to light, I thought I would offer a short defense of this multiple-stream / anyMatch strategy making reference to certain other parts of this thread:
As pointed out by eckes, anyMatch is optimized to return early and thus minimal time is spent reading the extra stream (especially for the case where prio1 is likely to match). In fact, anyMatch will only read the whole stream in the fallback (prio2) case, so for the average run you are only iterating through one-and-a-fraction list lengths.
Using the Collectors.groupingBy(...) method constructs a Map and two Lists in every case, while the approach above only creates at most a single List. The difference in memory overhead here will become quite significant as the size of results increases. The grouping is done for the entire stream, so even if the very first element happens to pass prio1, every element has to be checked against prio1.or(prio2) and then against prio1 once more.
groupingBy does not account for the case where prio1 and prio2 are not mutually exclusive. If prio2.test(e) can return true for some e which passes prio1, such elements will be missing within the fallback prio2 list. Using anyMatch and one filter at a time avoids this problem.
The line length and complexity of the above method seems far more manageable to me.
Just another approach that does not use anyMatch, but rather groups the entries before operating on the results.
Optional.of(results.stream()
.filter(prio1.or(prio2))
.collect(Collectors.groupingBy(prio1::test)))
.map(map -> map.getOrDefault(true, map.get(false)))
.ifPresent(System.out::println);
I used Optional so that you have a "one liner" (just formatted it, so that it gets more readable). Instead of ifPresent you could also just use orElseGet(Collections::emptyList) and save the result into a List<String>.
The groupingBy puts all prio1-matching entries from the prio1 and prio2 filtered entries into the key true and the remaining prio2-matching entries into false. If we haven't any entries in true, then the prio2-filtered entries are returned as default. If there aren't any prio1 or prio2-matching results, nothing happens.
Note that if you return the Map directly then you only have all prio2-matching entries in false if your filters are mutually exclusive.
Just make a condition:
final List<Foo> foo;
if (results.stream().anyMatch(prio1)) {
foo = results.stream().filter(prio1).collect(Collectors.toList());
} else {
foo = results.stream().filter(prio2).collect(Collectors.toList());
}
If you really want a one liner then you can do the following, but there's no way to get around streaming the list twice. I would argue that the if/else version is cleaner and easier to maintain.
final List<Foo> foo = results.stream()
.filter(results.stream().anyMatch(prio1)? prio1 : prio2)
.collect(Collectors.toList());
I have an array list with 5 elements each of which is an Enum. I want to build a method which returns another array list with the most common element(s) in the list.
Example 1:
[Activities.WALKING, Activities.WALKING, Activities.WALKING, Activities.JOGGING, Activities.STANDING]
Method would return: [Activities.WALKING]
Example 2:
[Activities.WALKING, Activities.WALKING, Activities.JOGGING, Activities.JOGGING, Activities.STANDING]
Method would return: [Activities.WALKING, Activities.JOGGING]
WHAT HAVE I TRIED:
My idea was to declare a count for every activity but that means that if I want to add another activity, I have to go and modify the code to add another count for that activity.
Another idea was to declare a HashMap<Activities, Integer> and iterate the array to insert each activity and its occurence in it. But then how will I extract the Activities with the most occurences?
Can you help me out guys?
The most common way of implementing something like this is counting with a Map: define a Map<MyEnum,Integer> which stores zeros for each element of your enumeration. Then walk through your list, and increment the counter for each element that you find in the list. At the same time, maintain the current max count. Finally, walk through the counter map entries, and add to the output list the keys of all entries the counts of which matches the value of max.
In statistics, this is called the "mode" (in your specific case, "multi mode" is also used, as you want all values that appear most often, not just one). A vanilla Java 8 solution looks like this:
Map<Activities, Long> counts =
Stream.of(WALKING, WALKING, JOGGING, JOGGING, STANDING)
.collect(Collectors.groupingBy(s -> s, Collectors.counting()));
long max = Collections.max(counts.values());
List<Activities> result = counts
.entrySet()
.stream()
.filter(e -> e.getValue().longValue() == max)
.map(Entry::getKey)
.collect(Collectors.toList());
Which yields:
[WALKING, JOGGING]
jOOλ is a library that supports modeAll() on streams. The following program:
System.out.println(
Seq.of(WALKING, WALKING, JOGGING, JOGGING, STANDING)
.modeAll()
.toList()
);
Yields:
[WALKING, JOGGING]
(disclaimer: I work for the company behind jOOλ)