Elixir 自定义展平实现中的空头

Elixir 自定义展平实现中的空头,elixir,Elixir,所以基本上,我尝试使用一些嵌套的递归来实现flant函数。问题是我得到了无限循环,当检查实际头部时,它是空的。我刚开始学习长生不老药,所以请不要对我太苛刻 defmoduletestdo def自定义_展平列表do 自定义展平列表,[] 结束 def自定义|U展平[h | t],累加器do 自定义展平[t],[自定义展平(h)|累加器] 结束 def自定义_展平[],累加器do IO.puts“调用空列表匹配#{acculator}” 枚举反向累加器 结束 def自定义_展平h,蓄能器do [h

所以基本上,我尝试使用一些嵌套的递归来实现flant函数。问题是我得到了无限循环,当检查实际头部时,它是空的。我刚开始学习长生不老药,所以请不要对我太苛刻

defmoduletestdo
def自定义_展平列表do
自定义展平列表,[]
结束
def自定义|U展平[h | t],累加器do
自定义展平[t],[自定义展平(h)|累加器]
结束
def自定义_展平[],累加器do
IO.puts“调用空列表匹配#{acculator}”
枚举反向累加器
结束
def自定义_展平h,蓄能器do
[h |累加器]
结束
结束

是这一行给您带来了问题:

    custom_flatten [t], [custom_flatten(h) | accumulator]
如果您的函数以
[h | t]=[1,2,3]
开头,
t
将是
[2,3]
,您将
[[2,3]]]
传递到下一个函数。该函数将看到
[h | t]=[[2,3]]
,因此
h
将是
[2,3]
t
将是
[]
,这将传递到下一个函数。然后,您的函数将无法重复
[h | t]=[[]]
,其中
h
[]
,而
t
[]

所以真正的问题是你不想包装你的
t
。用这样的东西替换上面的行应该可以解决无限递归问题

    custom_flatten t, [custom_flatten(h) | accumulator]

这条线给你带来了问题:

    custom_flatten [t], [custom_flatten(h) | accumulator]
如果您的函数以
[h | t]=[1,2,3]
开头,
t
将是
[2,3]
,您将
[[2,3]]]
传递到下一个函数。该函数将看到
[h | t]=[[2,3]]
,因此
h
将是
[2,3]
t
将是
[]
,这将传递到下一个函数。然后,您的函数将无法重复
[h | t]=[[]]
,其中
h
[]
,而
t
[]

所以真正的问题是你不想包装你的
t
。用这样的东西替换上面的行应该可以解决无限递归问题

    custom_flatten t, [custom_flatten(h) | accumulator]

看起来您已经在这样做了,但是一个好的策略是查看官方实现的功能。长生不老药的实施刚刚开始。以下是用Elixir重新编写的Erlang实现:

def展平([],acc),do:acc
def展平([h | t],acc)何时为列表(h)do
展平(h,展平(t,acc))
结束
def展平([h | t],acc)do
[h |展平(t,acc)]
结束
您的实现似乎存在一些问题

  • 终止条件是当第一个参数为空列表时。但是正如Brett也提到的,因为递归调用传递
    [t]
    ,这是一个包含尾部列表的单元素列表,所以终止条件永远不会发生
  • 您需要使用来检测下一个元素(
    h
    )是否是列表,以确定是否需要另一层递归,或者是否可以直接使用该元素
  • 看起来您的自定义行为正在反向构建列表。在这种情况下,您需要使用concatenation(
    ++
    )操作符,因为在反向构建时,我们必须动态展平子列表,然后将它们连接到累加器(在Erlang非反向实现中,尾部总是先展平,因此在这种情况下没有必要)。我们还需要确保只反转最终结果,否则内部列表在递归调用期间也会反转:
  • def展平(列表)操作
    列表
    |>展平([]))
    |>Enum.reverse()
    结束
    def展平([],acc),do:acc
    def展平([h | t],acc)何时为列表(h)do
    展平(t,展平(h,[])++acc)
    结束
    def展平([h | t],acc)do
    展平(t[h | acc])
    结束
    
    看起来您已经在这样做了,但是一个好的策略是查看官方实现的功能。长生不老药的实施刚刚开始。以下是用Elixir重新编写的Erlang实现:

    def展平([],acc),do:acc
    def展平([h | t],acc)何时为列表(h)do
    展平(h,展平(t,acc))
    结束
    def展平([h | t],acc)do
    [h |展平(t,acc)]
    结束
    
    您的实现似乎存在一些问题

  • 终止条件是当第一个参数为空列表时。但是正如Brett也提到的,因为递归调用传递
    [t]
    ,这是一个包含尾部列表的单元素列表,所以终止条件永远不会发生
  • 您需要使用来检测下一个元素(
    h
    )是否是列表,以确定是否需要另一层递归,或者是否可以直接使用该元素
  • 看起来您的自定义行为正在反向构建列表。在这种情况下,您需要使用concatenation(
    ++
    )操作符,因为在反向构建时,我们必须动态展平子列表,然后将它们连接到累加器(在Erlang非反向实现中,尾部总是先展平,因此在这种情况下没有必要)。我们还需要确保只反转最终结果,否则内部列表在递归调用期间也会反转:
  • def展平(列表)操作
    列表
    |>展平([]))
    |>Enum.reverse()
    结束
    def展平([],acc),do:acc
    def展平([h | t],acc)何时为列表(h)do
    展平(t,展平(h,[])++acc)
    结束
    def展平([h | t],acc)do
    展平(t[h | acc])
    结束