我需要生成一个这样的序列:
[1, 3, 5, 7, 9, 13, 17, 21, 25, 31, 37, 43, 49, 57, 65, 73, 81]
(本例中为17个数字)
算法是:
[1, (previous + 2), (previous + 2), (previous + 2), (previous + 2), (previous + 4), (previous + 4), (previous + 4), (previous + 4) ...
所以4个第一项是+2,接下来4个是+4,接下来是4 +.每4个项增加2.
我能够在Ruby中做一个快速和hacky版本:
def sequence
incr = 0
(0..16).each.inject([]) do |acc, counter|
acc << (acc.last || 1) + incr
incr += 2 if counter.modulo(4) == 0
acc
end
end
Run Code Online (Sandbox Code Playgroud)
但是我在Elixir做同样的问题 - 结果却是超级跛脚.像这样:
def sequence do
{ sequence, _ } =
0..16
|> Enum.reduce({[], 0}, fn(counter, {result, incr}) ->
last = List.last(result)
if last do
result = result ++ [last + incr]
else
result = [1]
end
if rem(counter, 4) == 0 do
incr = incr + 2
end
{result, incr}
end)
sequence
end
Run Code Online (Sandbox Code Playgroud)
显然我不应该在这里强制性地思考,但对于这个问题我不能:D我也确定有一种方法,管道更原子.
如何以Elixir方式解决这个问题?
我将启动累加器{[1], 0}以删除函数体中的特殊情况.List.last并且++通常不推荐,因为它们效率低(O(n)).Elixir中的惯用方法是反向构建列表并在结尾处反转列表.这意味着您的List.last逻辑现在可以通过匹配列表头部的模式来处理,这很便宜.您还应该收到incrif内部分配的警告.惯用的方法是做类似的事情incr = if ..., do: incr + 2, else: incr.
这是我写这个的方式:
(0..16)
|> Enum.reduce({[1], 0}, fn counter, {[h | _] = result, incr} ->
incr = if rem(counter, 4) == 0, do: incr + 2, else: incr
{[h + incr | result], incr}
end)
|> elem(0)
|> Enum.reverse
|> IO.inspect
Run Code Online (Sandbox Code Playgroud)
输出:
[1, 3, 5, 7, 9, 13, 17, 21, 25, 31, 37, 43, 49, 57, 65, 73, 81, 91]
Run Code Online (Sandbox Code Playgroud)