使用 Elixir 转换时隙

transforming timeslots using Elixir

我有这个数据,有时间段,我正在尝试将它们转换为同一天的 15 分钟间隔。

(长生不老药 1.10.4, 二郎 23.1.4)

[
  %{
    day: "fri",
    since: ~T[13:30:00],
    till: ~T[14:15:00],
  },
  %{
    day: "fri",
    since: ~T[15:30:00],
    till: ~T[16:30:00],
  },
]

我正在尝试将它转换成这个

[
  %{
    day: "fri",
    since: ~T[13:30:00],
    till: ~T[13:45:00],
  },
  %{
    day: "fri",
    since: ~T[13:45:00],
    till: ~T[14:00:00],
  },
  %{
    day: "fri",
    since: ~T[14:00:00],
    till: ~T[14:15:00],
  },
  %{
    day: "fri",
    since: ~T[15:30:00],
    till: ~T[15:45:00],
  },
  %{
    day: "fri",
    since: ~T[15:45:00],
    till: ~T[16:00:00],
  },
  %{
    day: "fri",
    since: ~T[16:00:00],
    till: ~T[16:15:00],
  },
  %{
    day: "fri",
    since: ~T[16:15:00],
    till: ~T[16:30:00],
  }
]

任何帮助都会很棒,我不知道如何处理枚举中的索引,所以我可以附加 since 和 till 地图。谢谢

假设没有重叠输入,我们可以使用来自 since 的无限流添加 15 分钟,直到达到 till

input = [
  %{day: "fri", since: ~T[13:30:00], till: ~T[14:15:00]},
  %{day: "fri", since: ~T[15:30:00], till: ~T[16:30:00]}
]

Enum.flat_map(input, fn 
  %{day: day, since: since, till: till} ->
    since
    |> Stream.iterate(& &1 |> Time.add(15 * 60) |> Time.truncate(:second))
    |> Stream.chunk_every(2, 1)
    |> Stream.map(fn [s, t] -> %{day: day, since: s, till: t} end)
    |> Enum.reduce_while([], fn %{till: t} = e, acc ->
         if(Time.compare(t, till) != :gt,
           do: {:cont, [e|acc]},
           else: {:halt, acc})
    end)
    |> Enum.reverse()
end)

对于输入的每个元素,我们必须将此项拆分为 15 分钟的块列表并累积它们:

defmodule SomeModule do
  @spec split(binary(), Time.t(), Time.t(), list()) :: list()
  def split(day, t1, t2, acc) do
    cond do
      t2 <= t1 -> acc
      true ->
        t = Time.add(t1, 15 * 60) |> Time.truncate(:second)
        cond do
          t < t2 -> split(day, t, t2, acc ++ [%{day: day, since: t1, till: t}])
          true -> split(day, t2, t2, acc ++ [%{day: day, since: t1, till: t2}])
        end
    end
  end

  @spec convert(list()) :: list()
  def convert(l) do
    Enum.reduce(l, [], fn x, acc ->
      acc ++ split(x.day, x.since, x.till, [])
    end)
  end
end

如果

l = [%{day: "fri",since: ~T[13:30:00],till: ~T[14:15:00]},%{day: "fri",since: ~T[15:30:00],till: ~T[16:30:00]}]

然后我们可以得到结果:

SomeModule.convert l

输出将是:

[
  %{day: "fri", since: ~T[13:30:00], till: ~T[13:45:00]},
  %{day: "fri", since: ~T[13:45:00], till: ~T[14:00:00]},
  %{day: "fri", since: ~T[14:00:00], till: ~T[14:15:00]},
  %{day: "fri", since: ~T[15:30:00], till: ~T[15:45:00]},
  %{day: "fri", since: ~T[15:45:00], till: ~T[16:00:00]},
  %{day: "fri", since: ~T[16:00:00], till: ~T[16:15:00]},
  %{day: "fri", since: ~T[16:15:00], till: ~T[16:30:00]}
]