我想计算数字列表中连续元素的差,例如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)
答案 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)
。在那个阶段,每个项目都与其下一个项目配对。