从列表中过滤单个项目

Filter single item from a List

鉴于:

iex(9)> list_of_maps = [%{"a" => 1, "b"  => 2, "c" => 3},%{"a" => 66, "b"  => 1, "c" => 9},%{"a" => 66, "b"  => 20, "c" => 8}]

我能做到:

iex(10)> Enum.filter(list_of_maps, &(&1["a"] == 1))                                                                                                                                                                
Enum.filter(list_of_maps, &(&1["a"] == 1))                                                                                                                                                                         
[%{"a" => 1, "b" => 2, "c" => 3}]

但是现在我害怕用每种语言编写的部分 - 获取此列表的第一个值以提取单个项目。

elixir 中是否有一些过滤列表的标准函数,如果应用过滤器后只有一个项目则返回单个项目,或者如果应用过滤器后返回许多项目则返回项目列表?喜欢:

iex(11)> Enum.filterr(list_of_maps, &(&1["a"] == 1))                                                                                                                                                                
Enum.filter(list_of_maps, &(&1["a"] == 1))                                                                                                                                                                         
%{"a" => 1, "b" => 2, "c" => 3}

iex(12)> Enum.filterr(list_of_maps, &(&1["a"] == 66))                                                                                                                                                                
Enum.filter(list_of_maps, &(&1["a"] == 66))                                                                                                                                                                         
[%{"a" => 66, "b"  => 1, "c" => 9},%{"a" => 66, "b"  => 20, "c" => 8}]]

只需将筛选后的列表输入 Enum.at/2

first = list_of_maps |> Enum.filter(&(&1["a"] == 66)) |> Enum.at(0)

无论大小如何,这将获取筛选列表的第一个元素。

此外,正如 Dogbert 在评论中提到的,您可以只使用 Enum.find/2 而不是过滤器来找到第一个匹配项。

Enum.find(list_of_maps, &(&1["a"] == 66))

Is there some standard function in elixir that filters a list, returning single item if there is only one item … or a list of items if there are numerous items

不,但是模式匹配让它变得微不足道:

def single_or_many([single]), do: single
def single_or_many(many), do: many

如果您想特殊处理空列表(在 'many' 案例之前):

def single_or_many([]), do: :nil

那么函数调用链为:

list_of_maps
|> Enum.filter(&(&1["a"] == 1))
|> single_or_many

从列表中查找一项

如果要过滤列表以仅获取一项,请使用Enum.find/2:

Enum.find(list_of_maps, fn m -> m["a"] == 1 end)

获取一个或一系列匹配项

要处理这两种情况,模式匹配是可行的方法:

defmodule MyEnum do
  def filter(list, fun) do
    list
    |> Enum.filter(fun)
    |> normalize
  end

  defp normalize([item]), do: item
  defp normalize(list),   do: list
end

然后你可以像这样使用它:

MyEnum.filter(list_of_maps, &(&1["a"] == 1))

如果有多个匹配项,它会return一个列表;如果只有一个匹配项,它会return一个地图本身。