我开始学习Elixir并遇到了一个我无法轻易解决的挑战.
我正在尝试创建一个带有Enumerable.t的函数,并返回另一个包含下n个项的Enumerable.t .它与Enum.chunk(e,n,1,[])的行为略有不同,因为数字迭代计数总是等于原始的可枚举计数.我还需要支持Streams
@spec lookahead(Enumerable.t, non_neg_integer) :: Enumerable.t
Run Code Online (Sandbox Code Playgroud)
使用doctest语法可以很好地说明这一点:
iex> lookahead(1..6, 1) |> Enum.to_list
[[1,2],[2,3],[3,4],[4,5],[5,6],[6]]
iex> lookahead(1..4, 2) |> Enum.to_list
[[1,2,3],[2,3,4],[3,4],[4]]
iex> Stream.cycle(1..4) |> lookahead(2) |> Enum.take(5)
[[1,2,3],[2,3,4],[3,4,1],[4,1,2],[1,2,3]]
iex> {:ok,io} = StringIO.open("abcd")
iex> IO.stream(io,1) |> lookahead(2) |> Enum.to_list
[["a","b","c"],["b","c","d"],["c","d"],["d"]]
Run Code Online (Sandbox Code Playgroud)
我已经研究过实现Enumerable.t协议,但还没有完全理解Enumerable.reduce接口.
有没有简洁/优雅的方式这样做?
我的用例是二进制流上的一个小的固定n值(1或2),因此优化版本的额外点.但是,为了学习Elixir,我对多个用例的解决方案很感兴趣.表现很重要.我将针对解决方案和发布的各种n值运行一些基准测试.
基准更新 - 2015年4月8日
已经发布了6个可行的解决方案.有关基准的详细信息,请访问https://gist.github.com/spitsw/fce5304ec6941578e454.基准测试在列表中运行,其中包含500个不同n值的项目.
对于n = 1,得到以下结果:
PatrickSuspend.lookahead 104.90 µs/op
Warren.lookahead 174.00 µs/op
PatrickChunk.lookahead 310.60 µs/op
PatrickTransform.lookahead 357.00 µs/op
Jose.lookahead 647.60 µs/op
PatrickUnfold.lookahead 1484000.00 µs/op
Run Code Online (Sandbox Code Playgroud)
对于n = 50,结果如下:
PatrickSuspend.lookahead 220.80 µs/op
Warren.lookahead 320.60 µs/op …Run Code Online (Sandbox Code Playgroud) elixir ×1