Elixir:计算连续元素差异的惯用方式?

时间:2018-11-01 23:16:46

标签: elixir

我想计算数字列表中连续元素的差,例如input = [1, 2, 3, 5]应该提供输出[-1, -1, -2]

我想出了两种看起来或多或少复杂的方法。有没有更简单,更惯用的方式做到这一点?

使用邮政编码:

Enum.zip(input, Enum.drop(input,1)) 
|> Enum.map(fn {x,y} -> x-y end)

使用扫描(过于复杂):

Enum.scan(input, [0, 0], fn x, [_delta, prev] -> [prev-x, x] end) 
|> Enum.map(fn [x, _y] -> x end) 
|> Enum.drop(1)

3 个答案:

答案 0 :(得分:2)

这是一个非常具体的用例,因此没有内置的解决方案可以完全做到这一点,但是我认为使用Enum.chunk_every/4惯用的: / p>

  

chunk_every(enumerable, count, step, leftover \\ [])

     

返回每个包含count个项目的列表列表,其中每个新块将step个元素开始枚举。


示例和解释:

input
|> Enum.chunk_every(2, 1, :discard)
|> Enum.map(fn [x, y] -> x - y end) 
  • 成员分为每个2个元素的列表
  • 从上一个列表的起始元素开始1步骤之后,下一个块开始
  • :discard意味着它会丢弃最后一个剩余的[5]块,因为我们不需要它。
  • 这将返回如下组中的元素:[[1, 2], [2, 3], [3, 5]]
  • 最后使用Enum.map
  • 计算每个块的差异

答案 1 :(得分:1)

实际上,所有操作都可以使用纯Enum.reduce/3完成。

input
|> Enum.reduce({nil, []}, fn
  e, {nil, acc} -> {e, acc}
  e, {prev, acc} -> {e, [prev - e | acc]}
end) # this does already contain the answer btw
|> elem(1)
|> :lists.reverse()
#⇒ [-1, -1, -2]

答案 2 :(得分:0)

虽然我更喜欢基于reduce的版本,但使用{ "url": "someURL" } { "url": "someURL2" } 有助于更好地理解问题。

首先,我们对输入进行转换:

zip

然后我们压缩[_ | next] = input input并计算减法:

next

input |> Enum.zip(next) |> Enum.map(fn {a, b} -> a - b end) 部分的值为input |> Enum.zip(next)。在那个阶段,每个项目都与其下一个项目配对。