Skip to content

Commit

Permalink
Polishing pull request #183
Browse files Browse the repository at this point in the history
1. flatOption -> mapPartial
2. JavaDoc, CHANGES, CHEATSHEET updated
3. Tests use stream generators
4. More efficient implementation
  • Loading branch information
amaembo committed Aug 5, 2018
1 parent f23c1ce commit 78c0490
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 103 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Expand Up @@ -2,6 +2,9 @@

Check also [MIGRATION.md](MIGRATION.md) for possible compatibility problems.

### 0.6.8
* [#183] Added: `StreamEx.mapPartial`, `EntryStream.mapToKeyPartial/mapToValuePartial/mapKeyValuePartial`

### 0.6.7
* [#76] Added: `StreamEx.zipWith` accepting `BaseStream` (so zipWith(IntStreamEx.ints()) works)
* [#131] Added: `StreamEx.ofCombinations`
Expand Down
1 change: 1 addition & 0 deletions CHEATSHEET.md
Expand Up @@ -116,6 +116,7 @@ Map pair of adjacent elements to the single element | `any.pairMap()`
Map only first or last element, leaving others as is | `any.mapFirst()/mapLast()`
Map stream element providing special mapper function for the first or last element | `any.mapFirstOrElse()/mapLastOrElse()`
Attach the first stream element to every stream element | `StreamEx.withFirst()`
Map only part of input elements using partial function which returns Optional | `StreamEx.mapPartial()`; `EntryStream.mapToKeyPartial()/mapToValuePartial()/mapKeyValuePartial()`

### flat-mapping

Expand Down
31 changes: 16 additions & 15 deletions src/main/java/one/util/streamex/AbstractStreamEx.java
Expand Up @@ -24,8 +24,8 @@
import static one.util.streamex.StreamExInternals.*;

/**
* Base class providing common functionality for {@link StreamEx} and {@link EntryStream}.
*
* Base class providing common functionality for {@link StreamEx} and {@link EntryStream}.
*
* @author Tagir Valeev
*
* @param <T> the type of the stream elements
Expand Down Expand Up @@ -197,14 +197,14 @@ public DoubleStreamEx flatMapToDouble(Function<? super T, ? extends DoubleStream
/**
* Returns a new stream containing all the elements of the original stream interspersed with
* given delimiter.
*
*
* <p>
* For example, {@code StreamEx.of("a", "b", "c").intersperse("x")} will yield a stream containing
* five elements: a, x, b, x, c.
*
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate operation</a>.
*
*
* @param delimiter a delimiter to be inserted between each pair of elements
* @return the new stream
* @since 0.6.6
Expand Down Expand Up @@ -374,7 +374,7 @@ public <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator,

/**
* {@inheritDoc}
*
*
* <p>
* If special <a
* href="package-summary.html#ShortCircuitReduction">short-circuiting
Expand Down Expand Up @@ -590,34 +590,35 @@ public <R> StreamEx<R> flatArray(Function<? super T, ? extends R[]> mapper) {
}

/**
* Returns a stream consisting of the results of replacing each element of
* this stream with the contents of the optional value produced by applying
* the provided mapping function to each element.
* Performs a mapping of the stream content to a partial function
* removing the elements to which the function is not applicable.
*
* <p>
* If the mapping function returns {@link Optional#empty()}, the original
* value will be removed from the resulting stream.
* value will be removed from the resulting stream. The mapping function
* may not return null.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* <p>
* The {@code flatOption()} operation has the effect of applying a
* The {@code mapPartial()} operation has the effect of applying a
* one-to-zero-or-one transformation to the elements of the stream, and then
* flattening the resulting elements into a new stream.
*
* @param <R> The element type of the new stream
* @param mapper a <a
* href="package-summary.html#NonInterference">non-interfering </a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function to apply to each element which produces an
* array of new values
* partial function to apply to each element which returns a present optional
* if it's applicable, or an empty optional otherwise
* @return the new stream
* @since 0.6.8
*/
public <R> StreamEx<R> flatOption(Function<? super T, ? extends Optional<? extends R>> mapper) {
return new StreamEx<>(stream().flatMap(value -> StreamEx.of(mapper.apply(value))), context);
public <R> StreamEx<R> mapPartial(Function<? super T, ? extends Optional<? extends R>> mapper) {
return new StreamEx<>(stream().map(value -> mapper.apply(value).orElse(null)).filter(Objects::nonNull),
context);
}

/**
Expand Down
186 changes: 110 additions & 76 deletions src/main/java/one/util/streamex/EntryStream.java
Expand Up @@ -183,32 +183,6 @@ public <KK> EntryStream<KK, V> flatMapToKey(BiFunction<? super K, ? super V, ? e
stream().flatMap(e -> withValue(mapper.apply(e.getKey(), e.getValue()), e.getValue())), context);
}

/**
* Returns an {@code EntryStream} consisting of the entries whose values are
* results of replacing source values with the contents of a mapped stream
* produced by applying the provided mapping function and converting the
* resulting optional to a stream.
*
* Keys are left intact.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param <KK> The type of new keys
* @param mapper a <a
* href="package-summary.html#NonInterference">non-interfering </a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function to apply to each key and value which produces an optional key
* @return the new stream
* @since 0.6.8
*/
public <KK> EntryStream<KK, V> flatOptionToKey(
BiFunction<? super K, ? super V, ? extends Optional<? extends KK>> mapper
) {
return flatMapToKey((key, value) -> StreamEx.of(mapper.apply(key, value)));
}

/**
* Returns an {@code EntryStream} consisting of the entries whose values are
* results of replacing source values with the contents of a mapped stream
Expand Down Expand Up @@ -261,33 +235,6 @@ public <VV> EntryStream<K, VV> flatMapToValue(
context);
}

/**
* Returns an {@code EntryStream} consisting of the entries whose values are
* results of replacing source values with the contents of a mapped stream
* produced by applying the provided mapping function and converting the
* resulting optional to a stream.
*
* Keys are left intact.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param <VV> The type of new values
* @param mapper a <a
* href="package-summary.html#NonInterference">non-interfering </a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* function to apply to each key and value which produces an optional
* new value
* @return the new stream
* @since 0.6.8
*/
public <VV> EntryStream<K, VV> flatOptionToValue(
BiFunction<? super K, ? super V, ? extends Optional<? extends VV>> mapper
) {
return flatMapToValue((key, value) -> StreamEx.of(mapper.apply(key, value)));
}

/**
* Returns a stream consisting of the results of replacing each element of
* this stream with the contents of a mapped stream produced by applying the
Expand All @@ -309,28 +256,6 @@ public <R> StreamEx<R> flatMapKeyValue(BiFunction<? super K, ? super V, ? extend
return this.<R> flatMap(toFunction(mapper));
}

/**
* Returns a stream consisting of the results of replacing each element of
* this stream with the contents of a mapped stream produced by applying
* the provided mapping function to each key-value pair and and converting
* the resulting optional to a stream.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate</a>
* operation.
*
* @param <R> The element type of the new stream
* @param mapper a non-interfering, stateless function to apply to each
* key-value pair which produces an optional new value
* @return the new stream
* @since 0.6.8
*/
public <R> StreamEx<R> flatOptionKeyValue(
BiFunction<? super K, ? super V, ? extends Optional<? extends R>> mapper
) {
return this.flatOption(toFunction(mapper));
}

/**
* Returns a new {@code EntryStream} which is a concatenation of this stream
* and the stream created from the supplied map entries.
Expand Down Expand Up @@ -584,14 +509,49 @@ public <VV> EntryStream<K, VV> mapValues(Function<? super V, ? extends VV> value
* operation.
*
* @param <R> The element type of the new stream
* @param mapper a non-interfering, stateless function to apply to key and
* @param mapper a <a
* href="package-summary.html#NonInterference">non-interfering </a>,
* <a href="package-summary.html#Statelessness">stateless</a> function to apply to key and
* value of each {@link Entry} in this stream
* @return the new stream
*/
public <R> StreamEx<R> mapKeyValue(BiFunction<? super K, ? super V, ? extends R> mapper) {
return this.<R> map(toFunction(mapper));
}

/**
* Performs a mapping of the stream keys and values to a partial function
* removing the elements to which the function is not applicable.
*
* <p>
* If the mapping function returns {@link Optional#empty()}, the original
* entry will be removed from the resulting stream. The mapping function
* may not return null.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* <p>
* The {@code mapKeyValuePartial()} operation has the effect of applying a
* one-to-zero-or-one transformation to the elements of the stream, and then
* flattening the resulting elements into a new stream.
*
* @param <R> The element type of the new stream
* @param mapper a <a
* href="package-summary.html#NonInterference">non-interfering </a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* partial function to apply to original keys and values which returns a present optional
* if it's applicable, or an empty optional otherwise
* @return the new stream
* @since 0.6.8
*/
public <R> StreamEx<R> mapKeyValuePartial(
BiFunction<? super K, ? super V, ? extends Optional<? extends R>> mapper
) {
return mapPartial(toFunction(mapper));
}

/**
* Returns an {@code EntryStream} consisting of the entries whose keys are
* modified by applying the given function and values are left unchanged.
Expand All @@ -611,6 +571,43 @@ public <KK> EntryStream<KK, V> mapToKey(BiFunction<? super K, ? super V, ? exten
e -> new SimpleImmutableEntry<>(keyMapper.apply(e.getKey(), e.getValue()), e.getValue())), context);
}

/**
* Performs a mapping of the stream content to a partial function
* removing the entries to which the function is not applicable.
*
* <p>
* If the mapping function returns an optional containing a new key,
* or {@link Optional#empty()} if function is not applicable to the entry.
* For successfully mapped keys the values are left intact. The mapping function
* may not return null.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* <p>
* The {@code mapToValuePartial()} operation has the effect of applying a
* one-to-zero-or-one transformation to the elements of the stream, and then
* flattening the resulting elements into a new stream.
*
* @param <KK> The type of new keys
* @param keyMapper a <a
* href="package-summary.html#NonInterference">non-interfering </a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* partial function to apply to original keys and values which returns a present optional
* if it's applicable, or an empty optional otherwise
* @return the new stream
* @since 0.6.8
*/
public <KK> EntryStream<KK, V> mapToKeyPartial(BiFunction<? super K, ? super V, ? extends Optional<? extends KK>> keyMapper) {
return new EntryStream<>(stream().map(
e -> {
KK mapping = keyMapper.apply(e.getKey(), e.getValue()).orElse(null);
return mapping != null ? new SimpleImmutableEntry<>(mapping, e.getValue()) : null;
}
).filter(Objects::nonNull), context);
}

/**
* Returns an {@code EntryStream} consisting of the entries whose keys are
* left unchanged and values are modified by applying the given function.
Expand All @@ -630,6 +627,43 @@ public <VV> EntryStream<K, VV> mapToValue(BiFunction<? super K, ? super V, ? ext
e -> new SimpleImmutableEntry<>(e.getKey(), valueMapper.apply(e.getKey(), e.getValue()))), context);
}

/**
* Performs a mapping of the stream content to a partial function
* removing the entries to which the function is not applicable.
*
* <p>
* If the mapping function returns an optional containing a new value,
* or {@link Optional#empty()} if function is not applicable to the entry.
* For successfully mapped values the keys are left intact. The mapping function
* may not return null.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* <p>
* The {@code mapToValuePartial()} operation has the effect of applying a
* one-to-zero-or-one transformation to the elements of the stream, and then
* flattening the resulting elements into a new stream.
*
* @param <VV> The type of new values
* @param valueMapper a <a
* href="package-summary.html#NonInterference">non-interfering </a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* partial function to apply to original keys and values which returns a present optional
* if it's applicable, or an empty optional otherwise
* @return the new stream
* @since 0.6.8
*/
public <VV> EntryStream<K, VV> mapToValuePartial(BiFunction<? super K, ? super V, ? extends Optional<? extends VV>> valueMapper) {
return new EntryStream<>(stream().map(
e -> {
VV mapping = valueMapper.apply(e.getKey(), e.getValue()).orElse(null);
return mapping != null ? new SimpleImmutableEntry<>(e.getKey(), mapping) : null;
}
).filter(Objects::nonNull), context);
}

/**
* Returns a stream consisting of the {@link Entry} objects which keys are
* the values of this stream elements and vice versa.
Expand Down
12 changes: 6 additions & 6 deletions src/test/java/one/util/streamex/EntryStreamTest.java
Expand Up @@ -397,7 +397,7 @@ public void testFlatMapValues() {
}

@Test
public void testFlatOptionToKey() {
public void testMapToKeyPartial() {
Map<Integer, Integer> original = new HashMap<>();
original.put(1, 1);
original.put(2, 5);
Expand All @@ -410,7 +410,7 @@ public void testFlatOptionToKey() {
expected.put(16, 4);

Map<Integer, Integer> actual = EntryStream.of(original)
.flatOptionToKey((key, value) -> {
.mapToKeyPartial((key, value) -> {
if (key.equals(value)) {
return Optional.of(key * value);
}
Expand All @@ -422,7 +422,7 @@ public void testFlatOptionToKey() {
}

@Test
public void testFlatOptionToValue() {
public void testMapToValuePartial() {
Map<Integer, Integer> original = new HashMap<>();
original.put(1, 1);
original.put(2, 5);
Expand All @@ -435,7 +435,7 @@ public void testFlatOptionToValue() {
expected.put(4, 16);

Map<Integer, Integer> actual = EntryStream.of(original)
.flatOptionToValue((key, value) -> {
.mapToValuePartial((key, value) -> {
if (key.equals(value)) {
return Optional.of(key * value);
}
Expand All @@ -447,7 +447,7 @@ public void testFlatOptionToValue() {
}

@Test
public void testFlatOptionKeyValue() {
public void testMapKeyValuePartial() {
Map<Integer, Integer> original = new HashMap<>();
original.put(1, 1);
original.put(2, 5);
Expand All @@ -456,7 +456,7 @@ public void testFlatOptionKeyValue() {

List<Integer> expected = asList(1, 9, 16);
List<Integer> actual = EntryStream.of(original)
.flatOptionKeyValue((key, value) -> {
.mapKeyValuePartial((key, value) -> {
if (key.equals(value)) {
return Optional.of(key * value);
}
Expand Down

0 comments on commit 78c0490

Please sign in to comment.