Эффективное сжатие списков неравной длины в Elixir - PullRequest
2 голосов
/ 12 мая 2019

Функция 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, потому что каждый требует полного обхода списка, и это внутри потенциально довольно большого сокращения.Я мог бы кэшировать длины внутри кортежа вместе с коротким и длинным списками, но это очень важно (хотя я сделаю это для увеличения производительности при необходимости).

Есть ли способ сделать это, чтоЯ не думал о?Возможно, совершенно другой подход?

1 Ответ

7 голосов
/ 12 мая 2019

Сделайте что-то вроде этого:

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}]

Это будет циклически проходить по элементам в более коротком списке, так как в более длинном списке есть данные.

...