【问题标题】:Better way to extract json map into struct将json映射提取到结构中的更好方法
【发布时间】:2018-08-08 00:28:00
【问题描述】:

我是 elixir 新手,我想解析一个 json 文件。其中一个部分是对象的问答数组。 [ { “问题ID”:1, “问题”:“信息:个人信息:名字”, “答案”:“乔” }, { “问题ID”:3, “问题”:“信息:个人信息:姓氏”, “答案”:“史密斯” }, ... ]

我知道我想要什么 questionId,我将为 1 = 名字,2 = 姓氏制作地图。

但目前我正在执行以下操作以将数据放入结构中。

defmodule Student do

  defstruct first_name: nil, last_name: nil, student_number:  nil

  defguard is_first_name(id) when id == 1

  defguard is_last_name(id) when id == 3

  defguard is_student_number(id) when id == 7

end

defmodule AFMC do

  import Student
  @moduledoc """
  Documentation for AFMC.
  """

  @doc """
  Hello world.

  ## Examples

      iex> AFMC.hello
      :world

  """
  def main do
    get_json()
    |> get_outgoing_applications
  end

  def get_json do
    with {:ok, body} <- File.read("./lib/afmc_import.txt"),
          {:ok,body} <- Poison.Parser.parse(body), do: {:ok,body}
  end

  def get_outgoing_applications(map) do
    {:ok,body} = map
    out_application = get_in(body,["outgoingApplications"])


    Enum.at(out_application,0)
    |> get_in(["answers"])
    |> get_person
  end

  def get_person(answers) do

    student = Enum.reduce(answers,%Student{},fn(answer,acc) ->

      if Student.is_first_name(answer["questionId"]) do

        acc = %{acc | first_name: answer["answer"]}

      end

      if Student.is_last_name(answer["questionId"]) do

        acc = %{acc | last_name: answer["answer"]}

      end

      if Student.is_student_number(answer["questionId"]) do

        acc = %{acc | student_number: answer["answer"]}

      end

      acc

    end)

    IO.inspect "test"
    s



  end


end

我想知道在不必执行 if 语句的情况下执行 get_person 的更好方法是什么。如果我知道我将在对象数组中将 1 映射到 questionId 1。 然后将数据保存到数据库中。

谢谢

【问题讨论】:

    标签: json parsing elixir


    【解决方案1】:

    我会存储 id 到字段名称的映射。这样你就不需要在 reduce 中使用任何 if 了。一些模式匹配也会使answer["questionId"]等变得不必要。

    defmodule Student do
      defstruct first_name: nil, last_name: nil, student_number: nil
    
      @fields %{
        1 => :first_name,
        3 => :last_name,
        7 => :student_number
      }
    
      def parse(answers) do
        Enum.reduce(answers, %Student{}, fn %{"questionId" => id, "answer" => answer}, acc ->
          %{acc | @fields[id] => answer}
        end)
      end
    end
    
    IO.inspect(
      Student.parse([
        %{"questionId" => 1, "question" => "", "answer" => "Joe"},
        %{"questionId" => 3, "question" => "", "answer" => "Smith"},
        %{"questionId" => 7, "question" => "", "answer" => "123"}
      ])
    )
    

    输出:

    %Student{first_name: "Joe", last_name: "Smith", student_number: "123"}
    

    编辑:跳过地图中不存在的 ID,更改:

    %{acc | @fields[id] => answer}
    

    到:

    if field = @fields[id], do: %{acc | field => answer}, else: acc
    

    【讨论】:

    • 我得到一个 key nil not found 错误。如果找不到 ID,则应跳过它。我假设这就是为什么会出现错误。
    • 我已经编辑了答案以包含对此的修复。让我知道它是否有效!
    • 有效!!谢谢,还在习惯模式匹配,我尝试过 if Map.has_key 但没有奏效,但我认为那是因为我忘记了 else 并返回了 acc。
    猜你喜欢
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    相关资源
    最近更新 更多