示例:我们有一个列表[1,2,3,4]
和一个fn &(&1 >= 3)
我想找回3
和[1,2,4]
目前我正在这样做:
index = Enum.find_index(list, func)
elem = Enum.at(list, index)
rest = List.delete_at(list, index)
这是3行代码,看起来像是可以缩短代码长度的通用模式。有没有更好的方法来实现这样的目标?
答案 0 :(得分:3)
要完成陈述的任务(仅限第一次发生),请使用始终有效的大锤:Enum.reduce_while/3
。
input = [1, 2, 3, 4]
input
|> Enum.with_index()
|> Enum.reduce_while({nil, []}, fn {e, idx}, {value, rest} ->
if e >= 3,
do: {:halt, {e, Enum.reverse(rest) ++ tl(Enum.slice(input, idx..-1))}},
else: {:cont, {value, [e | rest]}} end)
#⇒ {3, [1, 2, 4]}
此处仅需要with_index
技巧用于提高性能。找到该元素后,我们要立即停止迭代,因此需要下一个元素的索引才能将尾部批量添加到结果中。
另一种方法是使用Enum.split_while/2
with {h, [e | t]} <- Enum.split_while(input, fn x -> not(x >= 3) end),
do: {e, h ++ t}
#⇒ {3, [1, 2, 4]}
答案 1 :(得分:1)
假设完全有一个元素与您的函数匹配,则可以使用split_with
+模式匹配:
iex(1)> {[item], rest} = Enum.split_with([1,2,3,4], & &1 == 3)
{[3], [1, 2, 4]}
iex(2)> item
3
iex(3)> rest
[1, 2, 4]
当然,如果列表中有1个以上的匹配项,则会崩溃。如果您只想提取第一个,可以{[item | _], rest}
,但这仍会从rest
中删除所有它们,所以我不确定这是否就是您想要的。