///|
/// A closed time interval used by batch and streaming detectors.
pub(all) struct TimeWindow {
start : Int
end : Int
} derive(Eq, Debug)
///|
pub fn TimeWindow::new(start : Int, duration : Int) -> TimeWindow {
let safe_duration = if duration < 0 { 0 } else { duration }
{ start, end: start + safe_duration }
}
///|
pub fn TimeWindow::contains(self : TimeWindow, timestamp : Int) -> Bool {
timestamp >= self.start && timestamp <= self.end
}
///|
pub fn TimeWindow::duration(self : TimeWindow) -> Int {
self.end - self.start
}
///|
pub fn TimeWindow::overlaps(self : TimeWindow, other : TimeWindow) -> Bool {
self.start <= other.end && other.start <= self.end
}
///|
pub fn TimeWindow::intersection(
self : TimeWindow,
other : TimeWindow,
) -> TimeWindow? {
if self.overlaps(other) {
let start = if self.start > other.start { self.start } else { other.start }
let end = if self.end < other.end { self.end } else { other.end }
Some({ start, end })
} else {
None
}
}
///|
pub fn transactions_in_window(
transactions : Array[Transaction],
window : TimeWindow,
) -> Array[Transaction] {
let result : Array[Transaction] = []
for tx in transactions {
if window.contains(tx.occurred_at) {
result.push(tx)
}
}
result
}
///|
pub fn transactions_for_customer(
transactions : Array[Transaction],
customer : String,
) -> Array[Transaction] {
let result : Array[Transaction] = []
for tx in transactions {
if tx.customer_id == customer {
result.push(tx)
}
}
result
}
///|
pub fn transactions_for_account(
transactions : Array[Transaction],
account : String,
) -> Array[Transaction] {
let result : Array[Transaction] = []
for tx in transactions {
if tx.account_id == account {
result.push(tx)
}
}
result
}
///|
pub fn sort_by_time(transactions : Array[Transaction]) -> Array[Transaction] {
let result : Array[Transaction] = []
for tx in transactions {
let mut inserted = false
let mut index = 0
for old in result {
if !inserted && tx.occurred_at < old.occurred_at {
result.insert(index, tx)
inserted = true
}
index += 1
}
if !inserted {
result.push(tx)
}
}
result
}
///|
pub fn time_gaps(transactions : Array[Transaction]) -> Array[Int] {
let sorted = sort_by_time(transactions)
let gaps : Array[Int] = []
if sorted.length() > 1 {
for i in 1..