【问题标题】:Any easier way to get the first item in a list that matches a function, and return the item, and the list without that item?有没有更简单的方法来获取与函数匹配的列表中的第一个项目,并返回该项目以及没有该项目的列表?
【发布时间】:2021-05-11 02:15:21
【问题描述】:

示例:我们有一个列表 [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 行代码,看起来像是可以缩短的常见模式。有没有更好的方法来实现这样的目标?

【问题讨论】:

    标签: elixir


    【解决方案1】:

    要完成规定的任务(仅拆分到第一次出现),请使用始终有效的大锤: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]}
    

    【讨论】:

      【解决方案2】:

      假设只有一个元素与您的函数匹配,您可以使用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 中删除所有这些,所以我不确定这是否是你想要的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-02
        • 2016-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多