Skip to content

Commit b783c73

Browse files
committed
adding head() and find()
1 parent d62119d commit b783c73

File tree

4 files changed

+134
-0
lines changed

4 files changed

+134
-0
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
5+
import java.util.Iterator;
6+
import java.util.Optional;
7+
8+
/**
9+
* Retrieve the head element of an <code>Iterable</code>, wrapped in an <code>Optional</code>. If the
10+
* <code>Iterable</code> is empty, the result is <code>Optional.empty()</code>.
11+
*
12+
* @param <A> the Iterable element type
13+
*/
14+
public final class Head<A> implements Fn1<Iterable<A>, Optional<A>> {
15+
16+
private Head() {
17+
}
18+
19+
@Override
20+
public Optional<A> apply(Iterable<A> as) {
21+
Iterator<A> iterator = as.iterator();
22+
return iterator.hasNext()
23+
? Optional.of(iterator.next())
24+
: Optional.empty();
25+
}
26+
27+
public static <A> Head<A> head() {
28+
return new Head<>();
29+
}
30+
31+
public static <A> Optional<A> head(Iterable<A> as) {
32+
return Head.<A>head().apply(as);
33+
}
34+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn2;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.functions.Fn2;
5+
import com.jnape.palatable.lambda.functions.specialized.Predicate;
6+
7+
import java.util.Optional;
8+
import java.util.function.Function;
9+
10+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head;
11+
import static com.jnape.palatable.lambda.functions.builtin.fn2.DropWhile.dropWhile;
12+
13+
/**
14+
* Iterate the elements in an <code>Iterable</code>, applying a predicate to each one, returning the first element that
15+
* matches the predicate, wrapped in an <code>Optional</code>. If no elements match the predicate, the result is
16+
* <code>Optional.empty()</code>. This function short-circuits, and so is safe to use on potentially infinite
17+
* <code>Iterable</code>s that guarantee to have an eventually matching element.
18+
*
19+
* @param <A> the Iterable element type
20+
*/
21+
public final class Find<A> implements Fn2<Function<? super A, Boolean>, Iterable<A>, Optional<A>> {
22+
23+
private Find() {
24+
}
25+
26+
@Override
27+
public Optional<A> apply(Function<? super A, Boolean> predicate, Iterable<A> as) {
28+
return head(dropWhile(((Predicate<A>) predicate::apply).negate(), as));
29+
}
30+
31+
public static <A> Find<A> find() {
32+
return new Find<>();
33+
}
34+
35+
public static <A> Fn1<Iterable<A>, Optional<A>> find(Function<? super A, Boolean> predicate) {
36+
return Find.<A>find().apply(predicate);
37+
}
38+
39+
public static <A> Optional<A> find(Function<? super A, Boolean> predicate, Iterable<A> as) {
40+
return Find.<A>find(predicate).apply(as);
41+
}
42+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn1;
2+
3+
import com.jnape.palatable.traitor.runners.Traits;
4+
import org.junit.Test;
5+
import org.junit.runner.RunWith;
6+
7+
import java.util.Optional;
8+
9+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head;
10+
import static java.util.Arrays.asList;
11+
import static java.util.Collections.emptyList;
12+
import static org.junit.Assert.assertEquals;
13+
14+
@RunWith(Traits.class)
15+
public class HeadTest {
16+
17+
@Test
18+
public void returnsTheHeadOfNonEmptyIterable() {
19+
assertEquals(Optional.of(1), head(asList(1, 2, 3)));
20+
}
21+
22+
@Test
23+
public void isEmptyForEmptyIterable() {
24+
assertEquals(Optional.empty(), head(emptyList()));
25+
}
26+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.jnape.palatable.lambda.functions.builtin.fn2;
2+
3+
import org.junit.Test;
4+
5+
import java.util.Optional;
6+
7+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
8+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find;
9+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Iterate.iterate;
10+
import static java.util.Arrays.asList;
11+
import static org.junit.Assert.assertEquals;
12+
13+
public class FindTest {
14+
15+
@Test
16+
public void findsFirstElementMatchingPredicate() {
17+
assertEquals(Optional.of("three"),
18+
find(s -> s.length() > 3, asList("one", "two", "three", "four")));
19+
}
20+
21+
@Test
22+
public void isEmptyIfNoElementsMatchPredicate() {
23+
assertEquals(Optional.empty(),
24+
find(s -> s.length() > 5, asList("one", "two", "three", "four")));
25+
}
26+
27+
@Test
28+
public void shortCircuitsOnMatch() {
29+
assertEquals(Optional.of(0),
30+
find(constantly(true), iterate(x -> x + 1, 0)));
31+
}
32+
}

0 commit comments

Comments
 (0)