如何检查数组在长生不老药中是否按顺序和连续顺序
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.
带来的影响,就无法做到 elixir。
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
我想知道是否有一种方法可以确定数组是否按顺序排列且连续。例如
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.
带来的影响,就无法做到 elixir。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