Reputation: 4363
I have a sparse list of timestamps, let's dumb it down to:
val stamps = List(1,2,3,7,10,11)
Imagine I have a window size of three, what would be a Scala/Functional way to get the following output
valueWindowed (3, stamps) == List(
// Starting at timestamp 1 of stamps, we include the next values which are no bigger than the current value + the window size
List(1, 2, 3),
// Starting at timestamp 2 include the next values in this window
List(2, 3),
List(3), // ...
// This one is empty as the window starts at timestamp 4 and ends at 6 (inclusive)
List(),
// This one _does_ include 7, as the windows starts at 5 and ends at 7 (inclusive)
List(7),
List(7),
List(7),
List(10),
List(10,11),
List(10,11),
List(11)
)
I have the following implementation, but it looks very procedural, jammed into functional constructs. Also the complexity is max(stamps) * stamps size
def valueWindowed(step: Int, times: List[Int]) = {
for(j <- (1 to times.max).toIterator) yield{
times.dropWhile(_ < j) takeWhile(_ < j+step)
}
}
Upvotes: 0
Views: 296
Reputation: 41779
Here's a functional one that is O(N) - where N is the range of the numbers in times
, not the length of it. But it's not possible to do better than that since that's the size of your output.
def valueWindowed(step:Int, times:List[Int]) = {
(times :+ times.last+step)
.sliding(2)
.flatMap{case List(a,b) => Some(a)::List.fill(b-a-1)(None)}
.sliding(step)
.map(_.flatten)
}
The first sliding
and flatMap
expand the list so it has Some(x)
for all x in times
, and None
for all intermediate values (adding a sentinel value to get the last element included correctly). Then we take steps
windows and use flatten
to remove the None
/convert the Some
back
Upvotes: 1