在 Elixir 中有效压缩不等长列表
Efficiently zipping unequal length lists in Elixir
Elixir zip/2
函数压缩两个列表,在到达较短列表的末尾时停止。我一直在尝试做相反的事情——本质上是从较短的列表中复制项目,直到到达最长列表的末尾。
这是我的:
def zipReduce(m, n) when is_list(m) and is_list(n) do
{ long, short } = if length(m) > length(n)
do { m, n }
else { n, m }
end
Enum.reduce(0..Integer.mod(length(long), length(short)), [], fn i, acc ->
long
|> Enum.slice(length(short) * i, length(short))
|> Enum.zip(short)
|> Enum.into(acc)
end)
end
它确实有效,但我不喜欢所有这些对 length/1
的调用,因为每个调用都需要完整的列表遍历,并且它在潜在的相当大的缩减范围内。我可以将长度与短列表和长列表一起缓存在元组中,但这感觉非常必要(尽管我会在必要时为了提高性能而这样做)。
有没有我没想到的方法?可能是一种完全不同的方法?
做这样的事情:
Enum.zip(Stream.cycle(short), long)
例如
iex(1)> Enum.zip(Stream.cycle([1,2,3,4]), [:a, :b, :c, :d, :e, :f, :g, :h])
[{1, :a}, {2, :b}, {3, :c}, {4, :d}, {1, :e}, {2, :f}, {3, :g}, {4, :h}]
这将循环遍历较短列表中的元素,与较长列表中的数据一样多。
Elixir zip/2
函数压缩两个列表,在到达较短列表的末尾时停止。我一直在尝试做相反的事情——本质上是从较短的列表中复制项目,直到到达最长列表的末尾。
这是我的:
def zipReduce(m, n) when is_list(m) and is_list(n) do
{ long, short } = if length(m) > length(n)
do { m, n }
else { n, m }
end
Enum.reduce(0..Integer.mod(length(long), length(short)), [], fn i, acc ->
long
|> Enum.slice(length(short) * i, length(short))
|> Enum.zip(short)
|> Enum.into(acc)
end)
end
它确实有效,但我不喜欢所有这些对 length/1
的调用,因为每个调用都需要完整的列表遍历,并且它在潜在的相当大的缩减范围内。我可以将长度与短列表和长列表一起缓存在元组中,但这感觉非常必要(尽管我会在必要时为了提高性能而这样做)。
有没有我没想到的方法?可能是一种完全不同的方法?
做这样的事情:
Enum.zip(Stream.cycle(short), long)
例如
iex(1)> Enum.zip(Stream.cycle([1,2,3,4]), [:a, :b, :c, :d, :e, :f, :g, :h])
[{1, :a}, {2, :b}, {3, :c}, {4, :d}, {1, :e}, {2, :f}, {3, :g}, {4, :h}]
这将循环遍历较短列表中的元素,与较长列表中的数据一样多。