Idiomatic Elixir按特定非空键值过滤地图列表?

时间:2017-09-14 23:38:39

标签: elixir

我是elixir的新手,我正在试图找出重写这种红宝石方法的正确方法:

def filter_events(events)
  events.select { |event| event[:id].present? && event[:vhost].present? }
end
在长生不老药中。这就是我到目前为止所做的:

def filter_events(events) do
  Enum.filter(events, &(Map.has_key?(&1, :id) && Map.has_key?(&1, :vhost)))
end

有更好/更惯用的方法吗?

2 个答案:

答案 0 :(得分:3)

你的榜样很短暂,并不重要;它是可读的。但是,大多数示例(包括the ones in the docs)都使用内联/匿名函数:

Enum.filter(events, fn(event) ->
  Map.has_key?(event, :vhost) and Map.has_key?(event, :id)
end)

如果您正在寻找更聪明的东西,可以使用Kernel.match?()模式匹配。

Enum.filter(events, &match?(%{id: _, vhost: _}, &1))

或内联函数:

Enum.filter(events, fn(event) -> match?(%{id: _, vhost: _}, event) end)

由于您正在尝试检查密钥是否存在且其值不为空,因此以下内容应该有效:

Enum.filter(events, fn(event) ->
  !is_nil(event[:vhost]) and !is_nil(event[:id])
end)

答案 1 :(得分:1)

为了多样性,我会在这里提出这个答案。在我的理解中,最常用的方法是在过滤功能内进行模式匹配。它可能看起来更长,但更灵活。如果您的地图可能包含所需键的合法nil值(不是您的情况,可能,但仍然如此),它可以更好地处理。

def filter_events(events) do
  Enum.filter(events, fn
    %{id: nil} -> false        # or true if it might be nil
    %{vhost: nil} -> false     # or true if it might be nil
    %{id: _, vhost: _} -> true
    _ -> false
  end)  
end

在您的情况下,nil值无效并且应被视为缺少值时,可能会简化为:

def filter_events(events) do
  Enum.filter(events, fn
    %{id: id, vhost: vhost} when not is_nil(id)
                             and not is_nil(vhost) -> true
    _ -> false
  end)  
end

另一种方法是使用Kernel.for/1理解:

def filter_events(events) do
  for %{id: id, vhost: vhost} = e when
        not is_nil(id) and
        not is_nil(vhost) <- events, do: e
end

或者,没有模式匹配(较不惯用):

def filter_events(events) do
  for e <- events, !is_nil(e[:id]), !is_nil(e[:vhost]), do: e
end

或者,如果您不期望nil值,只需:

def filter_events(events) do
  for %{id: _, vhost: _} = e <- events, do: e
end