Skip to content

Commit 52e250b

Browse files
authored
FlowOps: debounce operator (#255)
1 parent d94cbe2 commit 52e250b

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

core/src/main/scala/ox/flow/FlowOps.scala

+19
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,25 @@ class FlowOps[+T]:
8686
if n != 0 && sampleCounter % n == 0 then emit(t)
8787
)
8888

89+
/** Remove subsequent, repeating elements
90+
*/
91+
def debounce: Flow[T] =
92+
debounceBy(identity)
93+
94+
/** Remove subsequent, repeating elements matching 'f'
95+
*
96+
* @param f
97+
* The function used to compare the previous and current elements
98+
*/
99+
def debounceBy[U](f: T => U): Flow[T] = Flow.usingEmitInline: emit =>
100+
var previousElement: Option[U] = None
101+
last.run(
102+
FlowEmit.fromInline: t =>
103+
val currentElement = f(t)
104+
if !previousElement.contains(currentElement) then emit(t)
105+
previousElement = Some(currentElement)
106+
)
107+
89108
/** Applies the given mapping function `f` to each element emitted by this flow, for which the function is defined, and emits the result.
90109
* If `f` is not defined at an element, the element will be skipped.
91110
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package ox.flow
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.Matchers
5+
import ox.*
6+
7+
class FlowOpsDebounceByTest extends AnyFlatSpec with Matchers:
8+
behavior of "debounceBy"
9+
10+
it should "not debounce if applied on an empty flow" in:
11+
val c = Flow.empty[Int]
12+
val s = c.debounceBy(_ * 2)
13+
s.runToList() shouldBe List.empty
14+
15+
it should "not debounce if applied on a flow containing only distinct f(value)" in:
16+
val c = Flow.fromValues(1 to 10: _*)
17+
val s = c.debounceBy(_ * 2)
18+
s.runToList() shouldBe (1 to 10)
19+
20+
it should "debounce if applied on a flow containing repeating f(value)" in:
21+
val c = Flow.fromValues(1, 1, 2, 3, 4, 4, 5)
22+
val s = c.debounceBy(_ * 2)
23+
s.runToList() shouldBe (1 to 5)
24+
25+
it should "debounce subsequent odd/prime numbers" in:
26+
val c = Flow.fromValues(1, 1, 1, 2, 4, 3, 7, 4, 5)
27+
val s = c.debounceBy(_ % 2 == 0)
28+
s.runToList() shouldBe List(1, 2, 3, 4, 5)
29+
30+
end FlowOpsDebounceByTest
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package ox.flow
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.Matchers
5+
import ox.*
6+
7+
class FlowOpsDebounceTest extends AnyFlatSpec with Matchers:
8+
behavior of "debounce"
9+
10+
it should "not debounce if applied on an empty flow" in:
11+
val c = Flow.empty[Int]
12+
val s = c.debounce
13+
s.runToList() shouldBe List.empty
14+
15+
it should "not debounce if applied on a flow containing only distinct values" in:
16+
val c = Flow.fromValues(1 to 10: _*)
17+
val s = c.debounce
18+
s.runToList() shouldBe (1 to 10)
19+
20+
it should "debounce if applied on a flow containing only repeating values" in:
21+
val c = Flow.fromValues(1, 1, 1, 1, 1)
22+
val s = c.debounce
23+
s.runToList() shouldBe List(1)
24+
25+
it should "debounce if applied on a flow containing repeating elements" in:
26+
val c = Flow.fromValues(1, 1, 2, 3, 4, 4, 5)
27+
val s = c.debounce
28+
s.runToList() shouldBe (1 to 5)
29+
30+
end FlowOpsDebounceTest

0 commit comments

Comments
 (0)