Skip to content

Commit 3fd3a63

Browse files
committed
Optimize '.after' method
1 parent d48fd71 commit 3fd3a63

2 files changed

Lines changed: 79 additions & 32 deletions

File tree

src/main/java/io/github/dgroup/enumerable4j/Enumerable.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -220,32 +220,41 @@ default X reduce(X idn, BinaryOperator<X> opr) {
220220
* @return The enumerable.
221221
*/
222222
default Enumerable<X> after(Predicate<X> prd) {
223-
return this.after(prd, this.size() - 1);
223+
return this.after(prd, this.size());
224224
}
225225

226226
/**
227227
* Returns an enumerable containing a certain number of elements of enumerable
228228
* after the first one which corresponds the condition.
229-
* If no predicate (null) is given, then 'this' is returned instead.
229+
* If no predicate (null) is given, then 'this' of the specified size is returned instead.
230230
* @param prd The function to match element after which enumerable elements should be returned.
231231
* @param size The number of elements the enumerable should be limited to.
232232
* @return The enumerable.
233233
*/
234234
default Enumerable<X> after(Predicate<X> prd, long size) {
235235
final Enumerable<X> out;
236-
if (prd == null) {
237-
out = this;
236+
if (size < 0) {
237+
throw new IllegalArgumentException(Long.toString(size));
238+
} else if (size == 0) {
239+
out = new Empty<>();
240+
} else if (prd == null) {
241+
out = new Linked<>(this.stream().limit(size).collect(Collectors.toList()));
238242
} else {
239-
int skip = 0;
243+
boolean found = false;
244+
out = new Linked<>();
245+
long cnt = size;
240246
for (final X elem : this) {
241-
++skip;
242-
if (prd.test(elem)) {
243-
break;
247+
if (!found && prd.negate().test(elem)) {
248+
continue;
249+
} else if (!found) {
250+
found = true;
251+
continue;
252+
}
253+
if (cnt > 0) {
254+
--cnt;
255+
out.add(elem);
244256
}
245257
}
246-
out = new Linked<>(
247-
this.stream().skip(skip).limit(size).collect(Collectors.toList())
248-
);
249258
}
250259
return out;
251260
}

src/test/java/io/github/dgroup/enumerable4j/AfterTest.java

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
package io.github.dgroup.enumerable4j;
2626

27+
import org.hamcrest.collection.IsEmptyIterable;
28+
import org.hamcrest.core.AllOf;
2729
import org.junit.jupiter.api.Test;
2830
import org.llorllale.cactoos.matchers.Assertion;
2931
import org.llorllale.cactoos.matchers.HasSize;
@@ -44,43 +46,46 @@ void nullPredicate() {
4446
new Assertion<>(
4547
"In case null-function the self enumerable is expected",
4648
new Linked<>(1, 2, 3, 4).after(null),
47-
new HasValues<>(1, 2, 3, 4)
49+
new AllOf<>(
50+
new HasSize(4),
51+
new HasValues<>(1, 2, 3, 4)
52+
)
4853
).affirm();
4954
}
5055

5156
@Test
5257
void allAfter() {
5358
new Assertion<>(
54-
"All elements after the first one which corresponds the condition",
55-
new Linked<>(1, 2, 3, 4, 5, 6, 7).after(n -> n > 2),
56-
new HasValues<>(4, 5, 6, 7)
59+
"Returns elements after the first one which corresponds the condition",
60+
new Linked<>(1, 2, 3, 4, 5).after(n -> n > 1),
61+
new AllOf<>(
62+
new HasSize(3),
63+
new HasValues<>(3, 4, 5)
64+
)
5765
).affirm();
5866
}
5967

6068
@Test
61-
void firstThreeAfter() {
69+
void firstTwoAfter() {
6270
new Assertion<>(
63-
"First 3 elements after the first one which corresponds the condition",
64-
new Linked<>(1, 2, 3, 4, 5, 6, 7).after(n -> n > 2, 3),
65-
new HasValues<>(4, 5, 6)
66-
).affirm();
67-
}
68-
69-
@Test
70-
void allStringsAfter() {
71-
new Assertion<>(
72-
"All string elements after the first one which corresponds the condition",
73-
new Linked<>("a", "b", "c", "d", "e").after(s -> s.equals("c")),
74-
new HasValues<>("d", "e")
71+
"Returns first 2 elements after the first one which corresponds the condition",
72+
new Linked<>("a", "b", "c", "d", "e").after(s -> s.equals("b"), 2),
73+
new AllOf<>(
74+
new HasSize(2),
75+
new HasValues<>("c", "d")
76+
)
7577
).affirm();
7678
}
7779

7880
@Test
7981
void firstTenAfter() {
8082
new Assertion<>(
8183
"The specified size can be greater than an actual enumerable size",
82-
new Linked<>(1, 2, 3, 4, 5).after(n -> n == 3, 10),
83-
new HasValues<>(4, 5)
84+
new Linked<>(1, 2, 3, 4, 5).after(n -> n == 2, 10),
85+
new AllOf<>(
86+
new HasSize(3),
87+
new HasValues<>(3, 4, 5)
88+
)
8489
).affirm();
8590
}
8691

@@ -89,16 +94,49 @@ void allAfterFirst() {
8994
new Assertion<>(
9095
"The first element of enumerable corresponds the condition",
9196
new Linked<>(1, 2, 3, 4, 5).after(n -> n < 10),
97+
new AllOf<>(
98+
new HasSize(4),
9299
new HasValues<>(2, 3, 4, 5)
100+
)
93101
).affirm();
94102
}
95103

96104
@Test
97105
void noneMatch() {
98106
new Assertion<>(
99-
"No one elements corresponds the condition, an empty collection is returned",
107+
"No one element corresponds the condition, an empty collection is returned",
100108
new Linked<>(1, 2, 3).after(n -> n < 0),
101-
new HasSize(0)
109+
new IsEmptyIterable<>()
110+
).affirm();
111+
}
112+
113+
@Test
114+
void zeroSize() {
115+
new Assertion<>(
116+
"If the size value is 0, an empty collection is returned",
117+
new Linked<>(1, 2, 3).after(n -> n < 10, 0),
118+
new IsEmptyIterable<>()
119+
).affirm();
120+
}
121+
122+
@Test
123+
void nullPredicateWithSize() {
124+
new Assertion<>(
125+
"In case null-function and specified size a enumerable of the size is expected",
126+
new Linked<>(1, 2, 3, 4).after(null, 2),
127+
new AllOf<>(
128+
new HasSize(2),
129+
new HasValues<>(1, 2)
130+
)
131+
).affirm();
132+
}
133+
134+
@Test
135+
void nullPredicateAndZeroSize() {
136+
new Assertion<>(
137+
"If the size value is 0, an empty collection is returned",
138+
new Linked<>(1, 2, 3).after(null, 0),
139+
new IsEmptyIterable<>()
102140
).affirm();
103141
}
104142

0 commit comments

Comments
 (0)