Фильтровать один элемент из списка

Дано:

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}]]

3 ответа

Решение

Найти один элемент из списка

Если вы хотите отфильтровать список, чтобы получить только один элемент, используйте 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))

Он вернет список, если есть несколько совпадений, или саму карту, если есть только одно совпадение.

Есть ли в elixir какая-то стандартная функция, которая фильтрует список, возвращая один элемент, если есть только один элемент... или список элементов, если имеется множество элементов

Нет, но сопоставление с образцом делает это тривиальным:

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

И если вы хотите обработать пустой список специально (до случая "многие"):

def single_or_many([]), do: :nil

Тогда цепочка вызова функции будет:

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

Просто перенаправьте отфильтрованный список в Enum.at/2

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

Это получит первый элемент отфильтрованного списка независимо от размера.

Кроме того, как отметил Догберт в комментариях, вы можете просто использовать Enum.find/2 вместо фильтра просто найти первое совпадение.

Enum.find(list_of_maps, &(&1["a"] == 66))
Другие вопросы по тегам