如何检查数组在长生不老药中是否按顺序和连续顺序

How to check if an array is in sequential and consecutive order in elixir

我想知道是否有一种方法可以确定数组是否按顺序排列且连续。例如

arr=[1,2,3,4,5]

Arr 将 return 为真,因为它是顺序且连续的

arr2=[1,2,3,4,56]

这将 return 错误,因为 56 不会紧接在 4 之后。我尝试了很多方法,但很难,因为没有循环

您可以使用 Enum.reduce,初始值为表示 {"is the list still consecutive and sequential?", "the last element processed by reduce"}.

的元组 {true, nil}
arr = [1, 2, 3, 4, 5]

{is_consecutive_and_sequential, _last_element} =
  Enum.reduce(arr, {true, nil}, fn
    current, {true, nil} when is_integer(current) -> {true, current}
    current, {true, previous} when is_integer(current) -> {current == previous + 1, current}
    current, {_anything, _previous} -> {false, current}
  end)

如果您的列表很长,可以使用 Enum.reduce_while 以获得更有效的解决方案:

{is_consecutive_and_sequential, _last_element} =
  Enum.reduce_while(arr, {true, nil}, fn
    current, {true, nil} when is_integer(current) ->
      {:cont, {true, current}}

    current, {true, previous} when is_integer(current) ->
      if current == previous + 1,
        do: {:cont, {true, current}},
        else: {:halt, {false, current}}

    current, {_anything, _previous} ->
      {:halt, {false, current}}
  end)

当助手不像普通的老式裸递归那样简单时就是这种情况。此外,这是一个很好的练习,因为如果不清楚地了解如何处理递归给 table.

带来的影响,就无法做到
defmodule Checkers do
  def seq?(input), do: do_seq?(input, nil)

  defp do_seq?([], _), do: true # we are done
  defp do_seq?([h | t], nil),
    do: do_seq?(t, h)           # entry
  defp do_seq?([h | t], ah) when ah == h - 1,
    do: do_seq?(t, h)           # success path
  defp do_seq?(_, _), do: false # ouch! we failed
end

Checkers.seq?([1, 2, 3, 4])
#⇒ true
Checkers.seq?([1, 3, 3, 4])
#⇒ false

完全正确Enum.reduce_while/3, suggested by @peaceful-james does basically exactly this under the hood。此解决方案的更简洁版本是

Enum.reduce_while(arr, true, fn
  curr, prev when prev == true or curr == prev + 1 ->
    {:cont, curr}
  _curr, _prev ->
    {:halt, false}
end) # returns truthy value if seq
[1,2,3,4,56] 
|> Enum.chunk_every(2, 1, :discard) 
|> Enum.all?(fn [x,y] -> y == x + 1 end)

应该使用几个标准库函数来完成您的要求。

chunk_every 给你一个滑动 window 将你的列表转换为 [[1, 2], [2, 3], [3, 4], [4, 56]] 为下面的下一个检查提供顺序基础。 丢弃部分是在最后删除单个元素,即 [1,2,3] |> Enum.chunk_every(2, 1) == [[1, 2], [2, 3], [3]]:discard 选项将遗漏最后一个(单个)项目(参见 Enum.chunk_every/3 的文档)

然后使用 Enum.all? 和给定的过滤器函数检查每对是否连续。

更新: 谦虚地包含了 Aleksei 的更正

这是使用 Enum.with_index

的另一种方法
    myList = [2,3,4,5,56]
    [head | _] = myList                         # gets first element in the 'array'
    res= Enum.with_index( myList, head) |>      # so [{2,2},{3,3},{4,4},{5,5},{56,6}]
         Enum.all?(&match?({x,x}, &1))
   if res == 1 do
       "sequential"
    else
       "not sequential"
    end

只是添加一个记录,这与 Aleksei 的递归非常接近,但没有辅助函数和额外的参数:

  def seq?([]), do: true
  def seq?([_]), do: true
  def seq?([i1, i2 | rest]) when i2 - i1 == 1, do: seq?([i2 | rest])
  def seq?([_ | _]) , do: false

使用标准函数(虽然可能更昂贵)

defp consecutive?(list) do
  [h | tl]= d = Enum.sort(list)
  d == Enum.to_list(h..List.last(tl))
end