Enum.reduce将字符串放入正确的列表中

时间:2018-05-04 14:36:08

标签: list dictionary enums elixir reduce

我有这个函数将字符串拆分成部分,我需要将这些部分放在params地图中的右边列表中。

parts = String.split(term_string, " ")

params = %{
  search_terms: [],
  wildcard_terms: [],
  minus_terms: [],
  room_terms: [],
  messages_to_terms: [],
  messages_from_terms: [],
  date_before_terms: [],
  date_after_terms: [],
  date_on_terms: [],
  date_during_terms: []
}

Enum.reduce(parts, params, fn p ->
  cond do
    String.ends_with?(p, "*") ->
      params[:wildcard_terms] = [p | params[:wildcard_terms]]

    true ->
      params[:search_terms] = [p | params[:search_terms]]
  end
end)

我现在收到cannot invoke remote function Access.get/2 inside match错误,而且我不确定如何解决这个问题。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

您需要在reduce函数中返回包含更新列表的新地图。一种方法是使用Map.update!

Enum.reduce(parts, params, fn p ->
  cond do
    String.ends_with?(p, "*") ->
      Map.update!(params, :wildcard_terms, fn ps -> [p | ps] end)

    true ->
      Map.update!(params, :search_terms, fn ps -> [p | ps] end)
  end
end)

答案 1 :(得分:0)

虽然@ Dogbert的解决方案肯定非常强大,但我会稍微重构一下这段代码以使其更简洁:

Enum.reduce(parts, params, fn p ->
  key =
    if String.ends_with?(p, "*") do
      :wildcard_terms
    else
      :search_terms
    end

  Map.update!(params, key, fn ps -> [p | ps] end)
end)

或者,如果你更喜欢冗长(并且慢 - 看下面有价值的Dogbert评论)但是易于阅读的方法(基于匹配mapper参数):

parts
|> Enum.map(&String.reverse/1)
|> Enum.reduce(params, fn
     <<"*", _::binary>> = p -> 
       %{params | wildcard_terms: [p | params.wildcard_terms]}
     p ->
       %{params | search_terms: [p | params.search_terms]}
   end)