Reputation: 2165
Is there a standard Elixir function that can insert an element at every nth index of a list?
With a function call and return like:
iex> List.insert_at_every([1,2,3,4,5], 2, Enum.random(["apple","banana"]))
[1, 2, "apple", 3, 4, "apple", 5]
Upvotes: 1
Views: 624
Reputation: 121000
NB the solution proposed by @Dogbert is better by all means, I am posting this for the sake of diversity.
To intersperse the list with a constant value, one might use Enum.chunk_every/2
and Enum.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]
This won’t work if you want to use a function to retrieve an element to intersperse on each iteration. In that case you are to implement the interspersion yourself:
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"]
The result above always contains a redundant trailing element, it should be shaved off afterwards:
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]
Upvotes: 3
Reputation: 222238
There isn't a built in function for this as far as I know, but this can be done using Enum.with_index
and Enum.flat_map
. When the remainder of the index and the second argument is the second argument minus 1, we insert the element + the callback into the resulting list, and just the element otherwise. I think it makes more sense that passing 1
as the every argument results in your example list instead of 2
. You can simply change every
with every - 1
if you want though.
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)
Output:
[1, "apple", 2, "apple", 3, "banana", 4, "banana", 5, "apple"]
[1, 2, "apple", 3, 4, "apple", 5]
[1, 2, 3, "apple", 4, 5]
Upvotes: 2