Skip to content

Commit

Permalink
Merge pull request #237 from dma1979/issue/#185-without
Browse files Browse the repository at this point in the history
Issue/#185 without
  • Loading branch information
amaembo authored Jan 11, 2021
2 parents 49e46f9 + a1531bb commit 1ceeeb0
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 5 deletions.
82 changes: 82 additions & 0 deletions src/main/java/one/util/streamex/EntryStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collector;
Expand Down Expand Up @@ -2284,4 +2285,85 @@ public static <K, V> EntryStream<K, V> generate(Supplier<? extends K> keySupplie
Stream.generate(() -> new SimpleImmutableEntry<>(keySupplier.get(), valueSupplier.get())),
StreamContext.SEQUENTIAL);
}

/**
* Returns an {@code EntryStream} consisting of the elements of this stream
* whose keys are not equal to any of supplied keys.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate</a> operation.
* May return itself if no keys were supplied.
*
* <p>
* Current implementation scans the supplied keys linearly for every stream element.
* If you have many keys, consider using more efficient alternative instead.
*
* <p>
* Future implementations may take advantage on using {@code hashCode()} or
* {@code compareTo} for {@code Comparable} objects to improve the performance.
*
* <p>
* If the {@code keys} array is changed between calling this method and finishing the stream traversal,
* then the result of the stream traversal is undefined: changes may or may not be taken into account.
*
* @param keys the keys to remove from the stream.
* @return the new stream
* @since 0.7.4
* @see #withoutValues(Object...)
* @see StreamEx#without(Object...)
*/
public EntryStream<K, V> withoutKeys(K... keys) {
if (keys.length == 0)
return this;
if (keys.length == 1)
return filter(entry -> !entry.getKey().equals(keys[0]));
return filter(entry -> {
for (K key : keys) {
if (entry.getKey().equals(key))
return false;
}
return true;
});
}

/**
* Returns an {@code EntryStream} consisting of the elements of this stream
* whose values are not equal to any of the supplied values.
*
* <p>
* This is an <a href="package-summary.html#StreamOps">intermediate</a> operation.
* May return itself if no values were supplied.
*
* <p>
* Current implementation scans the supplied values linearly for every stream element.
* If you have many values, consider using more efficient alternative instead.
*
* <p>
* Future implementations may take advantage on using {@code hashCode()} or
* {@code compareTo} for {@code Comparable} objects to improve the performance.
*
* <p>
* If the {@code values} array is changed between calling this method and finishing the stream traversal,
* then the result of the stream traversal is undefined: changes may or may not be taken into account.
*
* @param values the values to remove from the stream.
* @return the new stream
* @since 0.7.4
* @see #withoutKeys(Object...)
* @see StreamEx#without(Object...)
*/
public EntryStream<K, V> withoutValues(V... values) {
if (values.length == 0)
return this;
if (values.length == 1)
return filter(entry -> !entry.getValue().equals(values[0]));
return filter(entry -> {
for (V value : values) {
if (entry.getValue().equals(value))
return false;
}
return true;
});
}

}
64 changes: 64 additions & 0 deletions src/test/java/one/util/streamex/api/EntryStreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -814,4 +814,68 @@ public void testPrefixValues() {
Map<String, Integer> map = EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4).prefixKeys(String::concat).toMap();
assertEquals(EntryStream.of("a", 1, "ab", 2, "abc", 3, "abcd", 4).toMap(), map);
}

@Test
public void testWithoutKeys() {
assertEquals("Stream is not changed",
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4).toMap(),
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4)
.withoutKeys().withoutKeys().withoutKeys().toMap());

assertEquals(EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4).toMap(),
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4)
.withoutKeys().withoutKeys("A").withoutKeys("B", "C","D").toMap());

entryStream(() -> EntryStream.of(1, "a", 1, "b", 2, "c", 3, "d", 1, "e", 1, "f", 1, "g"),
s -> checkAsString("2->c;3->d", s.get().withoutKeys(1)));

assertEquals(EntryStream.of("b", 2, "d", 4).toMap(),
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4)
.withoutKeys("a").withoutKeys("c").toMap());

assertEquals(EntryStream.of("a", 1, "B", 4).toMap(),
EntryStream.of("a", 1, "A", 2, "b", 3, "B", 4)
.withoutKeys("A").withoutKeys("b").toMap());

entryStream(() -> EntryStream.generate(() -> "a", () -> 1).limit(10),
s -> checkAsString("", s.get().withoutKeys("a")));

entryStream(() -> EntryStream.of(1, "a", 1, "b", 2, "c", 3, "d", 4, "e", 4, "f", 1, "g"),
s -> checkAsString("2->c;3->d", s.get().withoutKeys(1, 4)));
assertEquals(EntryStream.of("b", 2, "d", 4).toMap(),
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4)
.withoutKeys("a", "c").toMap());
}

@Test
public void testWithoutValues() {
assertEquals("Stream is not changed",
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4).toMap(),
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4)
.withoutValues().withoutValues().withoutValues().toMap());

assertEquals(EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4).toMap(),
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4)
.withoutValues().withoutValues(6).withoutValues(7, 8).toMap());

entryStream(() -> EntryStream.of(1, "a", 1, "b", 2, "b", 3, "c", 4, "c", 5, "c", 6, "d"),
s -> checkAsString("1->a;1->b;2->b;6->d", s.get().withoutValues("c")));

assertEquals(EntryStream.of("c", 3, "d", 4).toMap(),
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4)
.withoutValues(1).withoutValues(2).toMap());

entryStream(() -> EntryStream.generate(() -> "a", () -> 1).limit(10),
s -> checkAsString("", s.get().withoutValues(1)));

entryStream(() -> EntryStream.of(1, "a", 1, "b", 2, "b", 3, "c", 4, "c", 5, "c", 6, "d"),
s -> checkAsString("1->a;6->d", s.get().withoutValues("b", "c")));
entryStream(() -> EntryStream.of(1, "a", 1, "A", 2, "b", 3, "B", 4, "c", 5, "C"),
s -> checkAsString("1->A;2->b;4->c;5->C", s.get().withoutValues("a", "B")));

assertEquals(EntryStream.of("c", 3, "d", 4).toMap(),
EntryStream.of("a", 1, "b", 2, "c", 3, "d", 4)
.withoutValues(1, 2).toMap());

}
}
9 changes: 5 additions & 4 deletions wiki/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Check also [MIGRATION.md](MIGRATION.md) for possible compatibility problems.

### 0.7.4
* [#091] Changed: API tests moved to the separate package.
* [#185] Added: `EntryStream.withoutKeys` and `EntryStream.withoutValues`.

### 0.7.3
* [#028] Added: `StreamEx.toCollectionAndThen`.
Expand All @@ -13,14 +14,14 @@ Check also [MIGRATION.md](MIGRATION.md) for possible compatibility problems.
* [#219] Changed: MoreCollectors now reject eagerly null parameters where possible; `MoreCollectors.last` throws NPE if last stream element is null.
* [#221] Fixed: `rangeClosed(x, x, step)` returned empty stream instead of stream of `x` if step absolute value is bigger than one.
* [#226] Added: `EntryStream.pairMap` (pairMap pulled up to AbstractStreamEx).
* [#229] Fixed: Some non-canonical nans were sorted incorrectly with `Double.reverseSorted()`.
* [#229] Fixed: some non-canonical nans were sorted incorrectly with `Double.reverseSorted()`.

### 0.7.2
* Fixed: accidental use of Java 9 API in CrossSpliterator
* Fixed: accidental use of Java 9 API in CrossSpliterator.

### 0.7.1
* [#202] Fixed: `StreamEx/EntryStream.ofTree` stack consumption is now limited
* Multi-release Jar is used to provide Java 9+ specializations
* [#202] Fixed: `StreamEx/EntryStream.ofTree` stack consumption is now limited.
* Multi-release Jar is used to provide Java 9+ specializations.

### 0.7.0
* [#193] Removed optimizations which rely on internal implementation details of Stream API (unwrap IteratorSpliterator;
Expand Down
4 changes: 3 additions & 1 deletion wiki/CHEATSHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ Stream of doubles from the `DoubleBuffer` | `DoubleStreamEx.of(DoubleBuffer)`
What I want | How to get it
--- | ---
Remove nulls | `StreamEx/EntryStream.nonNull()`
Remove entries which keys or values are null | `EntryStream.nonNullKeys()/nonNullValues()`
Remove entries whose keys or values are null | `EntryStream.nonNullKeys()/nonNullValues()`
Remove entries whose keys are equal to any of the supplied keys | `EntryStream.withoutKeys()`
Remove entries whose values are equal to any of the supplied values | `EntryStream.withoutValues()`
Remove elements by predicate | `any.remove()`
Remove given elements | `StreamEx/IntStreamEx/LongStreamEx.without()`
Remove by value extracted by supplied mapper function | `StreamEx.removeBy()`
Expand Down

0 comments on commit 1ceeeb0

Please # to comment.