Эликсир - отфильтровать список предметов с перекрывающимися датами с заданным диапазоном дат - PullRequest
1 голос
/ 25 апреля 2019

Мне нужно реорганизовать функцию, которая фильтрует список проектов по заданному диапазону дат:

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_date и end_date.Я хочу изменить его так, чтобы он возвращал проекты до тех пор, пока даты не совпадают.Пример:

  • дата начала проекта находится между отчетами start_date и end_date, но дата окончания проекта позже, чем end_date отчета, принять
  • дата окончания проекта находится между отчетами start_date и end_date, но дата начала проекта раньше, чем start_date отчета о принятии,
  • даты начала и окончания проекта находятся между start_date и end_date отчета о принятии, текущая реализация)

  • отчета start_date и end_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 ]

2 голосов
/ 25 апреля 2019

Просто объедините фильтры с логическим значением 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
0 голосов
/ 25 апреля 2019

Если вы можете с уверенностью предположить, что у вас никогда не будет однодневного отчета в тот же день, что и однодневный проект, вы можете просто проверить, что ваши сравнения не равны:

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
...