Elixir-过滤具有给定日期范围的重叠日期的项目列表

时间:2019-04-25 06:52:55

标签: elixir

我需要重构一个函数,该函数可以在给定的日期范围内过滤项目列表:

defp filter_by_date_range(projects, %{start_date: start_date, end_date: end_date} = _report) do
  projects
  |> Enum.filter(&Date.compare(&1.start_date, start_date) in [:gt, :eq])
  |> Enum.filter(&Date.compare(&1.end_date, end_date) in [:lt, :eq])
end

现在,它执行的操作是返回开始日期和结束日期介于报告的start_dateend_date之间的项目。我想对其进行修改,以便只要日期重叠即可返回项目。示例:

  • 项目的开始日期介于报告的start_dateend_date之间,但是项目的结束日期晚于报告的end_date,接受
  • 项目的结束日期介于报告的start_dateend_date之间,但是项目的开始日期早于报告的start_date,接受
  • 项目的开始和结束日期介于报告的start_dateend_date之间,接受(当前实现)

  • 报告的start_dateend_date介于项目的开始日期和结束日期之间,接受

  • 项目的开始和结束日期都早于报告的start_date,拒绝
  • 项目的开始和结束日期都晚于报告的end_date,拒绝

我想出了这个漂亮的解决方案,但是我能做些什么来改善它?

defp filter_by_date_range(projects, %{start_date: start_date, end_date: end_date}) do
  Enum.filter(projects, &do_dates_overlap?(&1, start_date, end_date))
end

defp do_dates_overlap?(project, start_date, end_date) do
  cond do
    Date.compare(project.end_date, start_date) == :lt -> false
    Date.compare(project.start_date, end_date) == :gt -> false
    true -> true
  end
end

2 个答案:

答案 0 :(得分:2)

只需将过滤器与布尔值OR结合起来即可:

defp filter_by_date_range(projects, %{start_date: sd, end_date: ed}) do
  Enum.filter(projects, &
    Date.compare(&1.start_date, sd) in [:gt, :eq] or
    Date.compare(&1.end_date, ed) in [:lt, :eq] or
    (
      Date.compare(&1.start_date, sd) == :lt and
      Date.compare(&1.end_date, ed) == :gt
    )
  )
end

,或者不太明确:

defp filter_by_date_range(projects, %{start_date: sd, end_date: ed}) do
  Enum.filter(projects, & not(
    Date.compare(&1.end_date, sd) == :lt or
    Date.compare(&1.start_date, ed) == :gt
  )
end

答案 1 :(得分:0)

如果您可以安全地做出假设,就不会与一个单日项目在同一天收到一份单日报告,则只需检查您的比较结果是否相等即可:

defp do_dates_overlap?(project, start_date, end_date) do
  Date.compare(project.end_date, start_date) != Date.compare(project.start_date, end_date)
end

如果您不能做这个假设,则可以将它们and一起使用:

defp do_dates_overlap?(project, start_date, end_date) do
  Date.compare(project.end_date, start_date) != :lt and Date.compare(project.start_date, end_date) != :gt
end