插入列表的每个第n个索引

时间:2017-10-21 20:47:33

标签: list insert elixir element

是否有标准的Elixir函数可以在列表的每个第n个索引处插入一个元素?

使用函数调用并返回如下:

iex> List.insert_at_every([1,2,3,4,5], 2, Enum.random(["apple","banana"]))
[1, 2, "apple", 3, 4, "apple", 5]

2 个答案:

答案 0 :(得分:2)

据我所知,目前还没有内置功能,但可以使用Enum.with_indexEnum.flat_map来完成。当索引的剩余部分和第二个参数是第二个参数减去1时,我们将元素+回调插入到结果列表中,否则只插入元素。我认为将1作为每个参数传递给您的示例列表而不是2更有意义。如果您愿意,可以随every更改every - 1

defmodule A do
  def insert_at_every(list, every, fun) do
    list
    |> Enum.with_index
    |> Enum.flat_map(fn {x, i} ->
      if rem(i, every) == every - 1 do
        [x, fun.()]
      else
        [x]
      end
    end)
  end
end

IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 1, fn -> Enum.random(["apple", "banana"]) end)
IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 2, fn -> Enum.random(["apple", "banana"]) end)
IO.inspect A.insert_at_every([1, 2, 3, 4, 5], 3, fn -> Enum.random(["apple", "banana"]) end)

输出:

[1, "apple", 2, "apple", 3, "banana", 4, "banana", 5, "apple"]
[1, 2, "apple", 3, 4, "apple", 5]
[1, 2, 3, "apple", 4, 5]

答案 1 :(得分:2)

NB @Dogbert提出的解决方案无论如何都更好,我为了多样性而发布这个。

要使用常量值散布列表,可以使用Enum.chunk_every/2Enum.intersperse/2

iex(1)> [1,2,3,4,5]
...(1)> |> Enum.chunk_every(2)
...(1)> |> Enum.intersperse("banana")
...(1)> |> List.flatten
#⇒ [1, 2, "banana", 3, 4, "banana", 5]

如果要在每次迭代时使用函数检索要散布的元素,则无效。在这种情况下,你要自己实现散布:

iex(2)> [1,2,3,4,5]
...(2)> |> Enum.chunk_every(2)
...(2)> |> Enum.map(& &1 ++ [Enum.random(~w|banana apple|)])
...(2)> |> List.flatten
#⇒ [1, 2, "banana", 3, 4, "apple", 5, "apple"]

上面的结果总是包含一个冗余的尾随元素,之后应该删掉它:

iex(3) > with [_ | result] <- :lists.reverse([1, 2, "banana", 3, 4, "apple", 5, "apple"]) do
...(3)>     :lists.reverse(result)
...(3)> end
#⇒ [1, 2, "banana", 3, 4, "banana", 5]