使用Clojure(嵌套列表等)从JSON中获取数据

时间:2018-04-13 20:13:20

标签: json clojure

我试图在各种网站上寻找答案,包括在这里看到一些看似相关的答案,但是我所尝试的一切都没有奏效。我正在尝试通过制作一个简单的JSON数据分析程序来学习Clojure。

我有以下示例数据(使用Cheshire来解析JSON文件,使用slurpparse-string):

({:id "0",
  :data [{:name "item1 x 1", :price {:GBP 9.99}} {:name "Delivery", :price {:GBP 3.49}}],
  :date {:date "2014-01-12T01:21:28.000Z"},
  :total {:GBP 1,
 {:id "1",
  :data [{:name "item2 x 1", :price {:GBP 9.99}}
          {:name "item3 x 1", :price {:GBP 9.99}}
          {:name "item4 x 1", :price {:GBP 9.99}}
          {:name "Admin", :price {:GBP 3.49}}],
  :date {:date "2013-01-12T07:37:04.000Z"},
  :total {:GBP 2},
 {:id "2",
  :data [{:name "item6 x 1", :price {:GBP 9.99}}
          {:name "item7 x 1", :price {:GBP 9.99}}
          {:name "item4 x 2", :price {:GBP 9.99}}
          {:name "item1 x 1", :price {:GBP 9.99}}
          {:name "item2 x 1", :price {:GBP 9.99}}
          {:name "Admin", :price {:GBP 3.49}}],
  :date {:date "2012-01-15T13:29:54.000Z"},
  :total {:GBP 3},
 {:id "3",
  :data [{:name "item8 x 1", :price {:GBP 9.99}}
          {:name "item4 x 1", :price {:GBP 9.99}}
          {:name "item5 x 1", :price {:GBP 9.99}}
          {:name "item9 x 1", :price {:GBP 9.99}}
          {:name "item4 x 1", :price {:GBP 9.99}}
          {:name "Admin", :price {:GBP 3.49}}],
  :date {:date "2014-01-17T06:22:23.000Z"},
  :total {:GBP 4},
  })

我相信这是地图或其他数据结构的持久向量(我正在努力克服clojure中的数据类型)。我正在尝试从中提取特定数据来回答分析问题,例如最常订购的项目,当天赚了多少钱等等。

我最初的问题只是尝试从此数据中的:name键中提取项目值。

我尝试使用map :data将数据隔离到项目名称和价格,然后使用type显示这是一个懒惰的序列。但是,我正在努力从名称键中获取数据(例如item1 x 1)。我已经尝试使用map函数和get-in函数无济于事。我认为这是由于数据的保存方式所以对此的任何解释都将非常感激!

这是我目前所坚持的,尽管如果有人确实想帮我解决更大的问题,然后获得最频繁的订单会很棒!

谢谢:)

1 个答案:

答案 0 :(得分:3)

我不得不重新格式化您的数据,因为您遗漏了一些尾随的}字符:

; Notice the single quote below!
(def data
  '( {:id    "0",
      :data  [{:name "item1 x 1", :price {:GBP 9.99}} {:name "Delivery", :price {:GBP 3.49}}],
      :date  {:date "2014-01-12T01:21:28.000Z"},
      :total {:GBP 1}},
     {:id    "1",
      :data  [{:name "item2 x 1", :price {:GBP 9.99}}
              {:name "item3 x 1", :price {:GBP 9.99}}
              {:name "item4 x 1", :price {:GBP 9.99}}
              {:name "Admin", :price {:GBP 3.49}}],
      :date  {:date "2013-01-12T07:37:04.000Z"},
      :total {:GBP 2}},
     {:id    "2",
      :data  [{:name "item6 x 1", :price {:GBP 9.99}}
              {:name "item7 x 1", :price {:GBP 1.23}}
              {:name "item4 x 2", :price {:GBP 9.99}}
              {:name "item1 x 1", :price {:GBP 9.99}}
              {:name "item2 x 1", :price {:GBP 9.99}}
              {:name "Admin", :price {:GBP 3.49}}],
      :date  {:date "2012-01-15T13:29:54.000Z"},
      :total {:GBP 3}},
     {:id    "3",
      :data  [{:name "item8 x 1", :price {:GBP 9.99}}
              {:name "item4 x 1", :price {:GBP 9.99}}
              {:name "item5 x 1", :price {:GBP 9.99}}
              {:name "item9 x 1", :price {:GBP 9.99}}
              {:name "item4 x 1", :price {:GBP 9.99}}
              {:name "Admin", :price {:GBP 3.49}}],
      :date  {:date "2014-01-17T06:22:23.000Z"},
      :total {:GBP 4}},
     )
  )

这是4个地图的 持续列表 ,每个地图都有嵌套的矢量和地图。要获得" item7"的价格你需要这样的东西:

  (->
    (nth data 2)
    (get-in [:data 1 :price :GBP]))

=> 1.23  ; where I changed the data to `1.23` to verify it worked

请务必结帐:

更新2018-8-28

想到一个更简单的方法。 Use the unlazy function,它将所有列表(懒惰或非懒惰)转换为向量。然后,您可以一步提取所需的项目:

(get-in (unlazy data) [2 :data 1 :price :GBP]) => 1.23

这是有效的,因为向量是一个关联数据结构,所以它就像一个从整数索引到元素值的映射。因此,get-in可以用于地图和矢量"索引"。