【问题标题】:Add new element to list将新元素添加到列表
【发布时间】:2016-06-02 10:01:10
【问题描述】:

我试图将新元素添加到列表中,如下所示:

iex(8)> l = [3,5,7,7,8] ++ 3
[3, 5, 7, 7, 8 | 3]
iex(9)> l
[3, 5, 7, 7, 8 | 3]

为什么我排在第五位

8 | 3

这是什么意思?
以及如何向列表中添加新元素?

--------更新--------
我尝试循环列表如下:

iex(2)> l = [1,2] ++ 3
[1, 2 | 3]
iex(3)> Enum.each(l, fn(x) -> IO.puts(x) end)
1
2
** (FunctionClauseError) no function clause matching in Enum."-each/2-lists^foreach/1-0-"/2
    (elixir) lib/enum.ex:604: Enum."-each/2-lists^foreach/1-0-"(#Function<6.54118792/1 in :erl_eval.expr/5>, 3)
    (elixir) lib/enum.ex:604: Enum.each/2

由于数字 2 的指针不是指向列表,而是指向值 3,如何循环列表?

【问题讨论】:

  • 谷歌搜索“Elixir Improper List”。该符号表示列表不正确。

标签: elixir


【解决方案1】:

只需按照 Elixir 文档将元素添加到列表中(并牢记性能 =)):

iex> list = [1, 2, 3]
iex> [0 | list]   # fast
[0, 1, 2, 3]
iex> list ++ [4]  # slow
[1, 2, 3, 4]

https://hexdocs.pm/elixir/List.html

【讨论】:

  • 因为 Elixir / Erlang 中的链表在内部是链表,所以在链表前面添加是一个快速的操作,因为你不需要重新创建链表尾部的链接。因此,在列表末尾添加元素将需要链表从后到前重新创建所有链接。
  • 在我看到这个 sn-p 之前,我不明白将元素附加到链表的计算成本会很高,而前置却很便宜,它显示了 List 底层的 cons 单元格:iex&gt; [1 | [2 | [3 | []]]] [1, 2, 3] 跨度>
【解决方案2】:

++ 运算符用于连接两个列表,那么您可能想要添加新元素的操作是将其放入列表中。然后,我认为您应该将 3 添加到另一个列表中:

iex(2)> l = [3,5,7,7,8] ++ [3]

[3, 5, 7, 7, 8, 3]

【讨论】:

  • 但是我想知道8 | 3是什么意思?
  • Elixir 中的列表是链表。 A | B 表示单元格 A 的指针指向 B。在您的情况下,这意味着列表的最后一个元素指向存储 3 的元素。
  • @SalvadorMedina 不,在这种情况下,8 | 3 表示不正确的列表。谷歌“Elixir 不当清单”,你会看到它是什么。
  • @OnorioCatenacci 哦,感谢您对符号的澄清!以这种方式学习真是太好了。
  • docs 的警告:“由于它们基于 cons 单元格的表示,将元素添加到列表总是很快(恒定时间),而随着列表的增长,添加变得更慢大小(线性时间): iex&gt; list = [1, 2, 3] iex&gt; [0 | list] # fast [0, 1, 2, 3] iex&gt; list ++ [4] # slow [1, 2, 3, 4]"
【解决方案3】:

首先:[1, 2 | 3] 是improper list 的符号。

第二:要执行 Enum.each,您尝试使用不正确的列表进行操作,代码如下所示:

匹配正确/不正确的列表也很容易。所以一个 正确列表的长度函数 len:

len([_|T]) -> 1 + len(T); len([]) -> 0. 我们明确匹配 终止[]。如果给定一个不正确的列表,这将生成一个 错误。而函数 last_tail 返回 a 的最后一个尾部 list 也可以处理不正确的列表:

last_tail([_|T]) -> last_tail(T); last_tail(尾巴) -> 尾巴。
%将匹配任何尾部

当然是Erlang code from @rvirding。翻译成 Elixir 并翻译成你在你的例子中给出的打印,它看起来像这样:

iex(6)> defmodule T do
...(6)>   defp print([h|t]) do
...(6)>     IO.puts(h)
...(6)>     print(t)
...(6)>   end
...(6)>   defp print(t) do
...(6)>     IO.puts(t)
...(6)>   end
...(6)>   def print_improper_list(il), do: print(il)
...(6)> end
iex:6: warning: redefining module T
{:module, T,
 <<70, 79, 82, 49, 0, 0, 5, 136, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 161, 131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115, 95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>,
 {:print_improper_list, 1}}
iex(7)> T.print_improper_list([1,2,3|4])
1
2
3
4
:ok

我把它作为一个练习让你弄清楚如何用 Enum.each 做到这一点。

【讨论】:

    【解决方案4】:

    Enum.concat加入

    示例:

    iex> new_elem = 5
    iex> Enum.concat([1, 2, 3], [new_elem])
    [1, 2, 3, 5]
    

    【讨论】:

    • 它在内部使用Kernel.++/2 来连接列表。
    【解决方案5】:

    “I”表示列表分为头尾,像这样[头|尾]尾巴]。如果您以这种方式对列表进行模式匹配,您可以操作列表的两个部分并使用 ++ 运算符进行连接。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-16
      • 1970-01-01
      相关资源
      最近更新 更多