Глубокая рекурсия уровня с эликсиром - PullRequest
1 голос
/ 18 июня 2019

Я работаю в файловой системе seaweedfs. и мы сохранили на нем файлы с правильной структурой каталогов как server / camera_id / snapshots / recordings / year

Я пытаюсь удалить пустые папки под годами.

def clean do
  cameras =
    Camera
    |> preload(:owner)
    |> order_by(desc: :created_at)
    |> Evercam.Repo.all()

  years = ["2015", "2016", "2017", "2018", "2019"]
  servers = [@seaweedfs_new, @seaweedfs_old, @seaweedfs_oldest]

  Enum.each(cameras, fn camera ->
    Enum.each(servers, fn server ->
      type = seaweefs_type(server)
      attribute = seaweedfs_attribute(server)
      url = server <> "/#{camera.exid}/snapshots/recordings/"

      Enum.each(years, fn year ->
        final_url = url <> year <> "/"
        request_from_seaweedfs(final_url, type, attribute)
      end)
    end)
  end)
end

когда последний запрос отправляется на год в request_from_seaweedfs(final_url, type, attribute)

либо выдает такой список, ["01", "02", "03"], либо []

в случае [] Я просто удаляю полное дерево как

url = server/gaol-yard/snapshots/recordings/2016/?recursive=true
hackney = [pool: :seaweedfs_download_pool, recv_timeout: 30_000]
HTTPoison.delete!("#{url}?recursive=true", [], hackney: hackney)

Но я хочу пойти глубже, если результат не [], то я хочу пойти на месяцы, такие как

months = ["01", "02", "03"]

final_url = url <> year <> "/" <> "{moth value from the list}"

для каждого месяца есть дни подряд, а затем для дней есть часы,

Я хочу проверить все это с помощью рекурсии, например, удалить дерево, если последний уровень или любой уровень пуст,

Например, если у камеры есть год, месяцы, дни и часы, но на последнем уровне, если час дает [], удалите все дерево.

Это может быть достигнуто с помощью Enum.each, что каждый раз, если я не получаю [], просто снова зацикливаюсь и поднимаюсь до последнего уровня, а там, где написано [], удаляю это, но можно ли это сделать через более программным способом? в рекурсии, а не так много каждого? любая помощь будет полезна спасибо

Ответы [ 2 ]

0 голосов
/ 19 июня 2019

Вот один из подходов.Измените текущую функцию на вызов recursive_delete с известными years:

Enum.each(cameras, fn camera ->
  Enum.each(servers, fn server ->
    type = seaweefs_type(server)
    attribute = seaweedfs_attribute(server)
    url = server <> "/#{camera.exid}/snapshots/recordings/"
    recursive_delete(years, url, type, attribute)
  end)
end)

А затем:

def recursive_delete([], _, _, _), do: :done

def recursive_delete(entries, url, type, attribute) do
  Enum.each(entries, fn entry ->
    entry_url = url <> entry <> "/"

    entry_url
    |> request_from_seaweedfs(type, attribute)
    |> recursive_delete(entry_url, type, attribute)
  end)
end
0 голосов
/ 18 июня 2019

Редактировать: неправильно понятый вопрос

Так что, если вы хотите сгенерировать комбинации с использованием рекурсии, я полагаю, вы могли бы передать свои аргументы (камеры, серверы, годы) в виде вложенного списка и рекурсивно построить комбинации (использоватьпервый список (камеры) и создайте список, передав остальные списки (серверы и годы) и т. д.).

Это имеет то преимущество, что вы можете передавать произвольное количество элементов или списков, и этобудет создавать комбинации вместо добавления еще одного уровня Enum.each, когда вы хотите добавить еще один уровень в URL.



defmodule Test do

  def perm(input, acc \\ [])
  def perm([], acc), do: acc
  def perm([first_arr | rest_arr], acc) do
    first_arr
    |> Enum.map(fn val ->
      perm(rest_arr, [val | acc])
    end)
  end

  def flat([fst | rst]) when is_list(fst) do
    case fst do
      [fst1 | _rst1] when is_list(fst1) -> flat(fst ++ rst)
      _ -> [fst] ++ flat(rst)
    end
  end
  def flat(other), do: other
end

cameras = ["gaol-yard", "gaol-yard-1", "gaol-yard-2"]
years =   ["2015", "2016", "2017", "2018", "2019"]
servers = ["seaweedfs_new", "seaweedfs_old", "seaweedfs_oldest"]
# input = [[1,2,3], [:a,:b,:c], [5.0, 6.0, 7.0]]

[cameras, years, servers] \
|> Test.perm() \
|> Test.flat \
|> Enum.map(&Enum.reverse/1)

Это должно сгенерировать что-то вроде

[
  ["gaol-yard", "2015", "seaweedfs_new"],
  ["gaol-yard", "2015", "seaweedfs_old"],
  ["gaol-yard", "2015", "seaweedfs_oldest"],
  ["gaol-yard", "2016", "seaweedfs_new"],
  ["gaol-yard", "2016", "seaweedfs_old"],
  ["gaol-yard", "2016", "seaweedfs_oldest"],
...
  "gaol-yard-1", "2015", "seaweedfs_old"],
  ["gaol-yard-1", "2015", "seaweedfs_oldest"],
  ["gaol-yard-1", "2016", "seaweedfs_new"],
...
  ["gaol-yard-2", "2019", "seaweedfs_new"],
  ["gaol-yard-2", "2019", "seaweedfs_old"],
  ["gaol-yard-2", "2019", "seaweedfs_oldest"]
]

, которое выможет объединяться в одну строку каждый

...