Skip to content

Commit af4d7c6

Browse files
authored
Merge pull request #3265 from kiendang/add-filternot
Add `Stream.filterNot`
2 parents 62ba4a1 + 03ad1e3 commit af4d7c6

File tree

3 files changed

+41
-0
lines changed

3 files changed

+41
-0
lines changed

core/shared/src/main/scala/fs2/Chunk.scala

+3
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ abstract class Chunk[+O] extends Serializable with ChunkPlatform[O] with ChunkRu
120120
Chunk.array(b.result()).asInstanceOf[Chunk[O]]
121121
}
122122

123+
/** Returns a chunk that has only the elements that do not satisfy the supplied predicate. */
124+
def filterNot(p: O => Boolean): Chunk[O] = filter(!p(_))
125+
123126
/** Returns the first element for which the predicate returns true or `None` if no elements satisfy the predicate. */
124127
def find(p: O => Boolean): Option[O] =
125128
iterator.find(p)

core/shared/src/main/scala/fs2/Stream.scala

+4
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,10 @@ final class Stream[+F[_], +O] private[fs2] (private[fs2] val underlying: Pull[F,
10821082
*/
10831083
def filter(p: O => Boolean): Stream[F, O] = mapChunks(_.filter(p))
10841084

1085+
/** Emits only inputs which do not match the supplied predicate.
1086+
*/
1087+
def filterNot(p: O => Boolean): Stream[F, O] = mapChunks(_.filterNot(p))
1088+
10851089
/** Like `filter`, but allows filtering based on an effect.
10861090
*
10871091
* Note: The result Stream will consist of chunks that are empty or 1-element-long.

core/shared/src/test/scala/fs2/StreamCombinatorsSuite.scala

+34
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,40 @@ class StreamCombinatorsSuite extends Fs2Suite {
567567
}
568568
}
569569

570+
group("filterNot") {
571+
property("1") {
572+
forAll { (s: Stream[Pure, Int], n0: Int) =>
573+
val n = (n0 % 20).abs + 1
574+
val predicate = (i: Int) => i % n == 0
575+
s.filterNot(predicate).assertEmits(s.toList.filterNot(predicate))
576+
}
577+
}
578+
579+
property("2") {
580+
forAll { (s: Stream[Pure, Double]) =>
581+
val predicate = (i: Double) => i - i.floor < 0.5
582+
val s2 = s.mapChunks(c => Chunk.array(c.toArray))
583+
assertEquals(s2.filterNot(predicate).toList, s2.toList.filterNot(predicate))
584+
}
585+
}
586+
587+
property("3") {
588+
forAll { (s: Stream[Pure, Byte]) =>
589+
val predicate = (b: Byte) => b < 0
590+
val s2 = s.mapChunks(c => Chunk.array(c.toArray))
591+
s2.filterNot(predicate).assertEmits(s2.toList.filterNot(predicate))
592+
}
593+
}
594+
595+
property("4") {
596+
forAll { (s: Stream[Pure, Boolean]) =>
597+
val predicate = (b: Boolean) => !b
598+
val s2 = s.mapChunks(c => Chunk.array(c.toArray))
599+
s2.filterNot(predicate).assertEmits(s2.toList.filterNot(predicate))
600+
}
601+
}
602+
}
603+
570604
property("find") {
571605
forAll { (s: Stream[Pure, Int], i: Int) =>
572606
val predicate = (item: Int) => item < i

0 commit comments

Comments
 (0)