Skip to content

Commit

Permalink
Move merge_ranges/1 to Util
Browse files Browse the repository at this point in the history
  • Loading branch information
jzimbel-mbta committed Aug 23, 2024
1 parent 2b4737f commit 71c3223
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 25 deletions.
55 changes: 55 additions & 0 deletions lib/transit_data/glides_report/util.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,61 @@ defmodule TransitData.GlidesReport.Util do
|> String.pad_leading(count, "0")
end

@doc """
Combines any consecutive, overlapping ranges in an enumerable.
All ranges in the enumerable must have a step of 1.
The returned list will be sorted.
iex> ranges = [1..2, 3..8, 7..12, 7..10, 15..20]
iex> merge_ranges(ranges)
[1..2, 3..12, 15..20]
iex> merge_ranges(Enum.reverse(ranges)) == merge_ranges(ranges)
true
iex> merge_ranges(Enum.shuffle(ranges)) == merge_ranges(ranges)
true
iex> merge_ranges([1..2//1, 2..0//-1])
** (ArgumentError) received range(s) with step != 1: [2..0//-1]
iex> merge_ranges([1..5//2, 3..12//3])
** (ArgumentError) received range(s) with step != 1: [1..5//2, 3..12//3]
iex> merge_ranges([])
[]
"""
@spec merge_ranges(Enumerable.t(Range.t())) :: list(Range.t())
def merge_ranges(ranges) do
bad_ranges = Enum.reject(ranges, &match?(_.._//1, &1))

unless bad_ranges == [],
do: raise(ArgumentError, "received range(s) with step != 1: #{inspect(bad_ranges)}")

ranges
|> Enum.sort_by(fn l.._r//1 -> l end)
|> Enum.reject(&(Range.size(&1) == 0))
|> Enum.chunk_while(
nil,
fn
range, nil ->
{:cont, range}

range, acc_range ->
if Range.disjoint?(range, acc_range),
do: {:cont, acc_range, range},
else: {:cont, merge_range_pair(acc_range, range)}
end,
fn
nil -> {:cont, nil}
final_acc -> {:cont, final_acc, nil}
end
)
end

defp merge_range_pair(l1..r1//1, l2..r2//1) do
min(l1, l2)..max(r1, r2)//1
end

@doc """
Formats the ratio of two numbers as a percentage.
"""
Expand Down
27 changes: 2 additions & 25 deletions reports/glides_terminal_departure_accuracy.livemd
Original file line number Diff line number Diff line change
Expand Up @@ -380,28 +380,6 @@ variances = [1, 2, 3, 5, 10]
# OVERALL VALUES #
##################

merge_sorted_ranges = fn l1.._r1//1, _l2..r2//1 ->
l1..r2//1
end

# Combines any consecutive, overlapping ranges in a pre-sorted list.
merge_ranges = fn ranges ->
Enum.chunk_while(
ranges,
nil,
fn
range, nil ->
{:cont, range}

range, acc_range ->
if Range.disjoint?(range, acc_range),
do: {:cont, acc_range, range},
else: {:cont, merge_sorted_ranges.(acc_range, range)}
end,
fn final_acc -> {:cont, final_acc, nil} end
)
end

# %{
# variance => %{
# stop_id => [actual_departure_range1, actual_departure_range2, ...]
Expand All @@ -418,9 +396,8 @@ actual_departure_windows_by_variance =
|> Map.new(fn {stop_id, timestamps} ->
time_ranges =
timestamps
|> Enum.sort()
|> Enum.map(fn t -> (t - variance_sec)..(t + variance_sec)//1 end)
|> merge_ranges.()
|> GlidesReport.Util.merge_ranges()

{stop_id, time_ranges}
end)
Expand Down Expand Up @@ -612,4 +589,4 @@ VegaLite.new(width: 500, height: 300, title: "Percent accurate by bucket size")
|> VegaLite.encode_field(:y, "Accuracy (% of total predictions)", type: :quantitative)
```

<!-- livebook:{"offset":21004,"stamp":{"token":"XCP.ATSOu_rP6RFgFvvRZ8paHaYkONVoffsyAdmyIND0CfyQSMJxlziipu5OMXp5vqkt5OHUi9quQtj_LASJHZq97-MmF2piU3uDc7VWoRBxn841hEBczhokS0oqxciRmKgWE8Do_GFXpC5Ob4dg5D_3FCiqht-iwg","version":2}} -->
<!-- livebook:{"offset":20496,"stamp":{"token":"XCP.-EXEMhs5k9Gi_mbKx8oXARcJZasMGsfSE8Rd-SjV-BpOlr5qKkoFFkLN7WMMR-aoIzpoqCPXgNUJnhb6tAKAHt0wSrpFxRQX2xuKH6KqDJu7CSFDic0DnbFpNjkOxgAPuUvD1GzcFo7YCOLg2nJAiOgHI5-ewA","version":2}} -->

0 comments on commit 71c3223

Please sign in to comment.