【问题标题】:How to work with nested data structures in Elixir如何在 Elixir 中使用嵌套数据结构
【发布时间】:2021-10-07 01:01:29
【问题描述】:

我正在尝试在 Elixir 中使用 Google Maps 地理编码 API,尽管我对这种语言有点陌生,因此我无法使用嵌套数据结构。

我正在使用 HTTPotion 从地理编码端点获取 JSON,并使用 JSEX 将其解析为 Elixir 数据结构(一系列嵌套列表和元组)。

defmodule Geocode do
  def fetch do
    HTTPotion.start
    result = HTTPotion.get "http://maps.googleapis.com/maps/api/geocode/json?address=Fairfax,%20Vermont&sensor=false"
    json   = JSEX.decode result.body
  end
end

现在将以下内容分配给 json。

{:ok, [{"results", [[{"address_components", [[{"long_name", "Fairfax"}, {"short_name", "Fairfax"}, {"types", ["locality", "political"]}], [{"long_name", "Franklin"}, {"short_name", "Franklin"}, {"types", ["administrative_area_level_2", "political"]}], [{"long_name", "Vermont"}, {"short_name", "VT"}, {"types", ["administrative_area_level_1", "political"]}], [{"long_name", "United States"}, {"short_name", "US"}, {"types", ["country", "political"]}]]}, {"formatted_address", "Fairfax, VT, USA"}, {"geometry", [{"bounds", [{"northeast", [{"lat", 44.772892}, {"lng", -72.92268890000001}]}, {"southwest", [{"lat", 44.6330508}, {"lng", -73.08477409999999}]}]}, {"location", [{"lat", 44.6654963}, {"lng", -73.01032}]}, {"location_type", "APPROXIMATE"}, {"viewport", [{"northeast", [{"lat", 44.772892}, {"lng", -72.92268890000001}]}, {"southwest", [{"lat", 44.6330508}, {"lng", -73.08477409999999}]}]}]}, {"types", ["locality", "political"]}]]}, {"status", "OK"}]}

我想从这个嵌套数据结构中提取纬度和经度。我尝试过使用模式匹配,但由于结构相当复杂,相应的模式有点像噩梦。虽然以下方法可行,但它可能不是一个好的解决方案。

{_, [{_, [[_, _, { _, [{_, [{_, [{_, lat}, {_, lgn}]}, _]}, _, _, _] }, _]]}, _]} = json

所以我的问题是从 Elixir 中深度嵌套的数据结构中提取值的最佳方法是什么?任何朝着正确方向的解决方案或轻推将不胜感激。

【问题讨论】:

    标签: elixir


    【解决方案1】:

    查看 Seth Falcon 的 ej 库的源代码:

    https://github.com/seth/ej

    它使用递归或多或少地完成了您想要做的事情。

    我不是 Elixir 专家,但您也许可以直接使用该库。

    【讨论】:

    • 您应该可以将 ej 与 Elixir 一起使用。像 ej 这样的工具是现在要走的路,但我们知道访问和更新嵌套数据结构并不像他们想象的那么容易,我们正在制定解决这些问题的提案。
    【解决方案2】:

    ej 库看起来是个不错的选择,但另外我可能会马上切入数据结构的核心:

    {:ok, [{"results", results}, {"status", status}]} = JSEX.decode result.body
    

    或者如果你总是只使用第一个结果:

    {:ok, [{"results", [geo_json | _]}, {"status", status}]} = JSEX.decode result.body
    

    然后我会在 geo_json 数据结构上使用 ej 库。

    【讨论】:

      【解决方案3】:

      您的JSEX.decode(result.body) 值的格式更好:

      {:ok,
       [
         {"results",
          [
            [
              {"address_components",
               [
                 [
                   {"long_name", "Fairfax"},
                   {"short_name", "Fairfax"},
                   {"types", ["locality", "political"]}
                 ],
                 [
                   {"long_name", "Franklin"},
                   {"short_name", "Franklin"},
                   {"types", ["administrative_area_level_2", "political"]}
                 ],
                 [
                   {"long_name", "Vermont"},
                   {"short_name", "VT"},
                   {"types", ["administrative_area_level_1", "political"]}
                 ],
                 [
                   {"long_name", "United States"},
                   {"short_name", "US"},
                   {"types", ["country", "political"]}
                 ]
               ]},
              {"formatted_address", "Fairfax, VT, USA"},
              {"geometry",
               [
                 {"bounds",
                  [
                    {"northeast", [{"lat", 44.772892}, {"lng", -72.92268890000001}]},
                    {"southwest", [{"lat", 44.6330508}, {"lng", -73.08477409999999}]}
                  ]},
                 {"location", [{"lat", 44.6654963}, {"lng", -73.01032}]},
                 {"location_type", "APPROXIMATE"},
                 {"viewport",
                  [
                    {"northeast", [{"lat", 44.772892}, {"lng", -72.92268890000001}]},
                    {"southwest", [{"lat", 44.6330508}, {"lng", -73.08477409999999}]}
                  ]}
               ]},
              {"types", ["locality", "political"]}
            ]
          ]},
         {"status", "OK"}
       ]}
      

      with/1 看起来很合适:

      with {:ok, json}                              <- JSEX.decode(result.body),
           [{"results", results}, {"status", "OK"}] <- json,
           [[_, _, {"geometry", geometry}, _]]      <- results,
           [_, {"location", location}, _, _]        <- geometry,
           [{"lat", lat}, {"lng", lng}]             <- location                  do
      
           # Do something with `lat` and `lng` here.
      
      end
      

      或许:

      {:ok, lat, lng} =
        with {:ok, json}                              <- JSEX.decode(result.body),
             [{"results", results}, {"status", "OK"}] <- json,
             [[_, _, {"geometry", geometry}, _]]      <- results,
             [_, {"location", location}, _, _]        <- geometry,
             [{"lat", lat}, {"lng", lng}]             <- location                  do
      
           {:ok, lat, lng}
      
        else
      
          _ -> {:error, "Failed to parse Google Maps API `geocode` response."}
      
        end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-26
        • 1970-01-01
        • 2014-04-27
        • 2018-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多