Clojure 执行;获得;在LazySeq的所有HashMap元素上

Clojure 执行;获得;在LazySeq的所有HashMap元素上,clojure,hashmap,lazy-sequences,Clojure,Hashmap,Lazy Sequences,我正在使用clojure.data.XML解析堆栈交换中的一些XML数据,例如,如果我解析投票数据,它将返回一个LazySeq,其中包含每行数据的HashMap 我试图做的是为每一行获取仅与特定键关联的值,例如,(获取投票[:Id:CreationDate])。我试过很多方法,大多数都会导致选角错误 最接近我需要的是使用(doall(map-get-vots[:Id:CreationDate])。然而,我现在遇到的问题是,我似乎只能返回第一行(即(1 2011-01-19T00:00:00.00

我正在使用
clojure.data.XML
解析堆栈交换中的一些XML数据,例如,如果我解析投票数据,它将返回一个LazySeq,其中包含每行数据的HashMap

我试图做的是为每一行获取仅与特定键关联的值,例如,
(获取投票[:Id:CreationDate])
。我试过很多方法,大多数都会导致选角错误

最接近我需要的是使用
(doall(map-get-vots[:Id:CreationDate])
。然而,我现在遇到的问题是,我似乎只能返回第一行(即
(1 2011-01-19T00:00:00.000)

这是一个可以在任何Clojure REPL或上运行的MCVE

理想情况下,我希望返回某种集合或映射,其中包含每行所需的值,最终目标是写入CSV文件之类的内容。例如,一个像


附加细节:如果这有任何帮助/兴趣,那么我用于获取上述惰性seq的代码如下所示:

(ns se-datadump.read-xml
  (require
    [clojure.data.xml :as xml])

(def xml-votes
  "<votes><row Id=\"1\" PostId=\"2\" VoteTypeId=\"2\" CreationDate=\"2011-01-19T00:00:00.000\" />  <row Id=\"2\" PostId=\"3\" VoteTypeId=\"2\" CreationDate=\"2011-01-19T00:00:00.000\" />  <row Id=\"3\" PostId=\"1\" VoteTypeId=\"2\" CreationDate=\"2011-01-19T00:00:00.000\" />  <row Id=\"4\" PostId=\"1\" VoteTypeId=\"2\" CreationDate=\"2011-01-19T00:00:00.000\" /></votes>")

(defn se-xml->rows-seq
  "Returns LazySequence from a properly formatted XML string,
  which contains a HashMap for every <row> element with each of its attributes.
  This assumes the standard Stack Exchange XML format, where a parent element contains
  only a series of <row> child elements with no further hierarchy."
  [xml-str]
  (let [xml-records (xml/parse-str xml-str)]
        (map :attrs (-> xml-records :content))))

; this returns a map identical as in the MCVE:
(def votes (se-xml->rows-seq xml-votes)
(ns-se-datadump.read-xml)
(要求
[clojure.data.xml:as-xml])
(def xml投票)
"      ")
(定义se xml->行序列
“从格式正确的XML字符串返回LazySequence,
它包含每个元素及其每个属性的HashMap。
这采用标准的堆栈交换XML格式,其中父元素包含
只有一系列没有进一步层次结构的子元素。”
[xml str]
(让[xml记录(xml/parse-str-xml-str)]
(映射:attrs(->xml记录:内容)))
;这将返回与MCVE中相同的映射:
(def投票(se xml->行序列xml投票)

您显然需要
juxt

(map (juxt :Id :CreationDate) votes)
;; => (["1" "2011-01-19T00:00:00.000"] ["2" "2011-01-19T00:00:00.000"] ["3" "2011-01-19T00:00:00.000"] ["4" "2011-01-19T00:00:00.000"])
如果您需要一张地图:

(into {} (map (juxt :Id :CreationDate) votes))
;; => {"1" "2011-01-19T00:00:00.000", "2" "2011-01-19T00:00:00.000", "3" "2011-01-19T00:00:00.000", "4" "2011-01-19T00:00:00.000"}

您显然需要
juxt

(map (juxt :Id :CreationDate) votes)
;; => (["1" "2011-01-19T00:00:00.000"] ["2" "2011-01-19T00:00:00.000"] ["3" "2011-01-19T00:00:00.000"] ["4" "2011-01-19T00:00:00.000"])
如果您需要一张地图:

(into {} (map (juxt :Id :CreationDate) votes))
;; => {"1" "2011-01-19T00:00:00.000", "2" "2011-01-19T00:00:00.000", "3" "2011-01-19T00:00:00.000", "4" "2011-01-19T00:00:00.000"}

首先,让我解释一下,你在代码板中建议的代码实际上在做什么。我怀疑这是你打算做的事情:

(println (doall (map get votes [:Id :CreationDate])))
关键部分是:
(map-get-voces[:Id:CreationDate])
这映射到两个集合:惰性序列“投票”和向量。每当映射到多个集合时,返回的惰性序列将与提供的最短集合一样长。
例如,可以映射有限集合和无限序列:

(map + (range) [1 2 3])
;; (0 3 5)
这就解释了为什么您的结果只有两项:

(map get votes [:Id :CreationDate])
减少到:

((get (votes 0) ([:Id :CreationDate] 0)
 (get (votes 1) ([:Id :CreationDate] 1))
((get {:Id "1",
       :PostId "2",
       :VoteTypeId "2",
       :CreationDate "2011-01-19T00:00:00.000"} :Id)
 (get {:Id "2",
       :PostId "3",
       :VoteTypeId "2",
       :CreationDate "2011-01-19T00:00:00.000"} :CreationDate))
减少到:

((get (votes 0) ([:Id :CreationDate] 0)
 (get (votes 1) ([:Id :CreationDate] 1))
((get {:Id "1",
       :PostId "2",
       :VoteTypeId "2",
       :CreationDate "2011-01-19T00:00:00.000"} :Id)
 (get {:Id "2",
       :PostId "3",
       :VoteTypeId "2",
       :CreationDate "2011-01-19T00:00:00.000"} :CreationDate))
最后减少到:

(1 2011-01-19T00:00:00.000)
这只是为了理解目的。如果编译器确实执行了这些步骤,则是另一个问题

doall
在这里是不必要的,因为
println
已经隐式地执行了此操作


如前所述。在您的情况下,您最好使用
juxt
,并且仅映射投票。如果您确实希望获得样本输出,您还需要将输出展平:

(flatten (map (juxt :Id :CreationDate) votes))

首先,让我解释一下,你在代码板中建议的代码实际上在做什么。我怀疑这是你打算做的事情:

(println (doall (map get votes [:Id :CreationDate])))
关键部分是:
(map-get-voces[:Id:CreationDate])
这映射到两个集合:惰性序列“投票”和向量。每当映射到多个集合时,返回的惰性序列将与提供的最短集合一样长。
例如,可以映射有限集合和无限序列:

(map + (range) [1 2 3])
;; (0 3 5)
这就解释了为什么您的结果只有两项:

(map get votes [:Id :CreationDate])
减少到:

((get (votes 0) ([:Id :CreationDate] 0)
 (get (votes 1) ([:Id :CreationDate] 1))
((get {:Id "1",
       :PostId "2",
       :VoteTypeId "2",
       :CreationDate "2011-01-19T00:00:00.000"} :Id)
 (get {:Id "2",
       :PostId "3",
       :VoteTypeId "2",
       :CreationDate "2011-01-19T00:00:00.000"} :CreationDate))
减少到:

((get (votes 0) ([:Id :CreationDate] 0)
 (get (votes 1) ([:Id :CreationDate] 1))
((get {:Id "1",
       :PostId "2",
       :VoteTypeId "2",
       :CreationDate "2011-01-19T00:00:00.000"} :Id)
 (get {:Id "2",
       :PostId "3",
       :VoteTypeId "2",
       :CreationDate "2011-01-19T00:00:00.000"} :CreationDate))
最后减少到:

(1 2011-01-19T00:00:00.000)
这只是为了理解目的。如果编译器确实执行了这些步骤,则是另一个问题

doall
在这里是不必要的,因为
println
已经隐式地执行了此操作


如前所述。在您的情况下,您最好使用
juxt
,并且仅映射投票。如果您确实希望获得样本输出,您还需要将输出展平:

(flatten (map (juxt :Id :CreationDate) votes))

我不确定我是否完全理解您的意图。您是否可以提供一个手动创建的示例结果?这样更容易判断。@AntonHarald我添加了一个示例所需结果,希望这有助于使其更清楚。我不确定我是否完全理解您的意图。您是否可以提供一个手动创建的示例结果?这样更容易理解告诉。@AntonHarald我添加了一个期望结果的示例,希望这有助于使其更清楚。这是有意义的,不是那样想的。谢谢你的解释!这是有意义的,不是那样想的。谢谢你的解释!