Skip to content

Commit

Permalink
Add findIndexed operator
Browse files Browse the repository at this point in the history
  • Loading branch information
aNNiMON committed Mar 25, 2017
1 parent ecd3d52 commit 0f9fdaa
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 0 deletions.
57 changes: 57 additions & 0 deletions stream/src/main/java/com/annimon/stream/Stream.java
Expand Up @@ -1669,6 +1669,63 @@ public boolean noneMatch(Predicate<? super T> predicate) {
return match(predicate, MATCH_NONE);
}

/**
* Finds the first element and its index that matches the given predicate.
*
* <p>This is a short-circuiting terminal operation.
*
* <p>Example:
* <pre>
* predicate: (index, value) -&gt; index + value == 7
* stream: [1, 2, 3, 4, 5, 2, 0]
* index: [0, 1, 2, 3, 4, 5, 6]
* result: Optional.of(IntPair(3, 4))
* </pre>
*
* @param predicate the predicate to find value
* @return an {@code Optional} with {@code IntPair}
* or {@code Optional.empty()} if stream is empty or no value was found.
* @since 1.1.8
*/
public Optional<IntPair<T>> findIndexed(IndexedPredicate<? super T> predicate) {
return findIndexed(0, 1, predicate);
}

/**
* Finds the first element and its index that matches the given predicate.
*
* <p>This is a short-circuiting terminal operation.
*
* <p>Example:
* <pre>
* from: 0
* step: 10
* predicate: (index, value) -&gt; index + value == 42
* stream: [1, 11, 22, 12, 40]
* index: [0, 10, 20, 30, 40]
* result: Optional.of(IntPair(20, 22))
* </pre>
*
* @param from the initial value of the index (inclusive)
* @param step the step of the index
* @param predicate the predicate to find value
* @return an {@code Optional} with {@code IntPair}
* or {@code Optional.empty()} if stream is empty or no value was found.
* @since 1.1.8
*/
public Optional<IntPair<T>> findIndexed(int from, int step,
IndexedPredicate<? super T> predicate) {
int index = from;
while (iterator.hasNext()) {
final T value = iterator.next();
if (predicate.test(index, value)) {
return Optional.of(new IntPair<T>(index, value));
}
index += step;
}
return Optional.empty();
}

/**
* Returns the first element wrapped by {@code Optional} class.
* If stream is empty, returns {@code Optional.empty()}.
Expand Down
@@ -0,0 +1,48 @@
package com.annimon.stream.streamtests;

import com.annimon.stream.IntPair;
import com.annimon.stream.Optional;
import com.annimon.stream.Stream;
import com.annimon.stream.function.IndexedPredicate;
import org.junit.Test;
import static com.annimon.stream.test.hamcrest.OptionalMatcher.isEmpty;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

public final class FindIndexed {

@Test
public void testFindIndexed() {
IntPair<Integer> result = Stream.rangeClosed(1, 10)
.findIndexed(sumEquals(7))
.get();
assertThat(result.getFirst(), is(3));
assertThat(result.getSecond(), is(4));
}

@Test
public void testFindIndexedWithStartAndStep() {
IntPair<Integer> result = Stream.of(1, 11, 22, 12, 40)
.findIndexed(0, 10, sumEquals(42))
.get();
assertThat(result.getFirst(), is(20));
assertThat(result.getSecond(), is(22));
}

@Test
public void testFindIndexedNoMatch() {
Optional<IntPair<Integer>> result = Stream.range(0, 10)
.findIndexed(sumEquals(42));
assertThat(result, isEmpty());
}


private static IndexedPredicate<Integer> sumEquals(final int sum) {
return new IndexedPredicate<Integer>() {
@Override
public boolean test(int index, Integer value) {
return index + value == sum;
}
};
}
}

0 comments on commit 0f9fdaa

Please sign in to comment.