如何获得Elixir范围的尾部

时间:2016-12-02 14:57:41

标签: pattern-matching elixir

这可能是一个微不足道的问题,但我无法理解它。

我只想在一个范围上进行模式匹配,得到头部和尾部。

这是我试过的:

iex(1)> [h|t] = [1..3]
[1..3]
iex(2)> h
1..3
iex(3)> t
[]

正如您所看到的,它没有达到我的预期。我的期望是h = 1t = [2,3]

如何让头部和尾部脱离范围?这甚至可能吗?

4 个答案:

答案 0 :(得分:6)

首先,[1..3]是一个包含1个范围的列表,而不是范围。其次,范围本身不是列表,它只是一个包含2个值的结构:第一个和最后一个值(Map.from_struct(1..10) #=> %{first: 1, last: 10})。如果您希望将范围的头部和尾部作为列表,则需要首先将范围转换为列表:

iex(1)> range = 1..3
1..3
iex(2)> list = Enum.to_list(range)
[1, 2, 3]
iex(3)> [h | t] = list
[1, 2, 3]
iex(4)> h
1
iex(5)> t
[2, 3]

请注意,这取决于您正在做什么,效率非常低。范围占用非常少的内存(Struct + 2整数键)。列表将占用与列表中的项目数成比例的空间。根据您正在做的事情,可能有一种比将范围转换为列表更好的方法。

答案 1 :(得分:3)

这应该效果更好

iex(42)> range = 1..100     
1..100
iex(43)> _..last = range    
1..100
iex(44)> last
100

答案 2 :(得分:0)

最有效的方法可能就是从底层AST中获取它:

iex(6)> Macro.escape(1..10)
{:%{}, [], [__struct__: Range, first: 1, last: 10]}

...因此

{:%{}, [], [__struct__: Range, first: head, last: tail]} = Macro.escape(range)

iex(10)> head
1
iex(11)> tail
10

编辑:正在使用quote,但Macro.escape似乎更强大

答案 3 :(得分:0)

借用edwinallenz的答案(很优雅,但仅返回最后一个元素),以下内容返回首尾,同时也与OP的想法保持紧密联系:

iex(1)> first..last = 1..5
1..5
iex(2)> [h | t] = [first | first+1..last]
[1 | 2..5]

Dogbert的答案解释了Elixir范围上的语法糖:脱下妆容,在1..5下找到结构%Range{first: first, last: last}。 因此,上面直接使用基础结构的东西将是一件笨拙的事情:

iex(1)> r = %Range{first: 1, last: 5}     
1..5
iex(2)> [h | t] = [r.first | %Range{first: r.first+1, last: r.last}]
[1 | 2..5]