Snapshot of main at 9f39a6e1e (2026-11-02)
This commit is contained in:
commit
6ccf1792d7
2580 files changed
+1040202
No files matched your search
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Stats;
|
||||
|
||||
/**
|
||||
* Which keys occur inside a date window that only ever moves forward.
|
||||
*
|
||||
* Built for the network time-lapse: its layers are windows over a day-ordered
|
||||
* list of [day, key] events - "traded in the month ending on this step",
|
||||
* "traded before this date" - and each step moves them on by a week or a
|
||||
* month. Two pointers walk the events once in total, so all steps together
|
||||
* cost one pass, and each step reports only the keys that entered or left.
|
||||
*
|
||||
* Days are 'Y-m-d' strings, which compare correctly as strings.
|
||||
*/
|
||||
class SlidingWindow
|
||||
{
|
||||
/** @var array<string,int> Occurrences of each key inside the window. */
|
||||
private array $count = [];
|
||||
|
||||
private int $enter = 0;
|
||||
|
||||
private int $leave = 0;
|
||||
|
||||
private int $size;
|
||||
|
||||
/** @param array<array{0:string, 1:string}> $events [day, key], ordered by day */
|
||||
public function __construct(private array $events)
|
||||
{
|
||||
$this->size = count($events);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the window to [$start, $end] (inclusive; null start = no lower
|
||||
* bound) and return what entered and left since the previous call.
|
||||
*
|
||||
* Both bounds may only move forward.
|
||||
*
|
||||
* @return array{added: array<string>, removed: array<string>}
|
||||
*/
|
||||
public function slideTo(?string $start, string $end): array
|
||||
{
|
||||
$before = [];
|
||||
|
||||
while ($this->enter < $this->size && $this->events[$this->enter][0] <= $end) {
|
||||
$key = $this->events[$this->enter++][1];
|
||||
$before[$key] ??= ($this->count[$key] ?? 0) > 0;
|
||||
$this->count[$key] = ($this->count[$key] ?? 0) + 1;
|
||||
}
|
||||
|
||||
if ($start !== null) {
|
||||
while ($this->leave < $this->enter && $this->events[$this->leave][0] < $start) {
|
||||
$key = $this->events[$this->leave++][1];
|
||||
$before[$key] ??= ($this->count[$key] ?? 0) > 0;
|
||||
|
||||
if (--$this->count[$key] === 0) {
|
||||
unset($this->count[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$added = [];
|
||||
$removed = [];
|
||||
|
||||
foreach ($before as $key => $was) {
|
||||
$now = isset($this->count[$key]);
|
||||
|
||||
if ($now && !$was) {
|
||||
$added[] = $key;
|
||||
} elseif (!$now && $was) {
|
||||
$removed[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
return ['added' => $added, 'removed' => $removed];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user