Elixir — Передача нескольких списков в качестве параметров функции

#list #function #pagination #elixir

#Список #функция #разбивка на страницы #elixir

Вопрос:

Я новичок в Elixir, но мои поиски в Google и чтение не нашли мне решения моей текущей проблемы. Я видел только примеры в книгах и руководствах с передачей одного параметра списка в функцию следующим образом: [ head | tail ] .

 defmodule Math do
  def double_each([head|tail]) do
    [head * 2| double_each(tail)]
  end

  def double_each([]) do
    []
  end
end
 

Мне нужно передать два списка, а затем выполнить с ними некоторые действия, например:

 defmodule Pagination do
  def getPaginatedList([], _, _, _) do
    []
  end

  def getPaginatedList([list], [paginated], f, l) when f == 1 do
    Enum.take(list, l)
  end

  def getPaginatedList(_, [paginated], f, l) when l <= f do
    paginated
  end

  def getPaginatedList([list], [paginated] \ [], f, l) do
    getPaginatedList(tl(list), paginated    hd(list), f, l - 1)
  end
end
 

Однако я получаю сообщение об ошибке о несоответствии предложения функции при передаче списка для a и списка для b, как в приведенной ниже ошибке:

 iex(23)> Pagination.getPaginatedList(a, b, 1, 2)
** (FunctionClauseError) no function clause matching
      in Pagination.getPaginatedList/4
    pagination.ex:2: Pagination.getPaginatedList([1, 2, 3, 4, 5], [], 1, 2)
 

Любые идеи о том, что я могу делать неправильно? (Прошу прощения, если это простой вопрос для ответа. Я не смог найти никакого ответа после нескольких часов поиска и игры с этим.)

Ответ №1:

Ваши проблемы связаны с совпадением шаблона аргумента списка. Для list аргументов paginated и вам не нужно заключать их в список, так как на самом деле вы будете сопоставлять их во вложенном списке. Кроме того, в Elixir принято использовать регистр snake для имен функций. Попробуйте сделать это:

 defmodule Pagination do
  def get_paginated_list([], _, _, _) do
    []
  end

  def get_paginated_list(list, paginated, f, l) when f == 1 do
    Enum.take(list, l)
  end

  def get_paginated_list(_, paginated, f, l) when l <= f do
    paginated
  end

  def get_paginated_list(list, paginated \ [], f, l) do
    get_paginated_list(tl(list), paginated    hd(list), f, l - 1)
  end
end
 

Ответ №2:

@Chris решил проблему с сообщением об ошибке, с которым вы столкнулись, я только добавлю, что сигнатуры методов не очень «эликсирны».

Следующие подписи методов больше соответствуют духу и стилю кодирования языка (я изменил некоторые имена параметров, чтобы они были более удобочитаемыми):

 defmodule Pagination do
  def get_paginated_list([], _, _, _) do
    []
  end

  def get_paginated_list(list, _, page_num, page_size) when page_num == 1 do
    Enum.take(list, page_size)
  end

  def get_paginated_list(_, paginated, page_num, page_size) when page_size <= page_num do
    paginated
  end

  def get_paginated_list([head | tail], paginated \ [], page_num, page_size) do
    get_paginated_list(tail, paginated    [head], page_num, page_size - 1)
  end
end
 

Я не совсем уверен, какой должна быть семантика вашего кода, но для разбивки на страницы, я думаю, вы могли бы взглянуть на Enum.chunk/4 то, что вы могли бы использовать следующим образом:

 defmodule Pagination do   
  def get_paginated_list(list, page_num, page_size) do
    list |> Enum.chunk(page_size, page_size, []) |>  Enum.at(page_num)
  end
end

Pagination.get_paginated_list([1, 2, 3, 4, 5], 1, 3)
# => [4, 5]
Pagination.get_paginated_list([1, 2, 3, 4, 5], 0, 3)
# => [1, 2, 3]
Pagination.get_paginated_list([1, 2, 3, 4, 5], 2, 3)
# => nil