对 LazySeq 的所有 HashMap 元素执行 "get"
Perform "get" on all HashMap elements of a LazySeq
我正在使用 clojure.data.xml
解析来自 Stack Exchange 的一些 XML 数据,例如,如果我解析 Votes 数据,它 return 是一个包含每行数据的 HashMap 的 LazySeq。
我想做的是为每一行获取仅与某些键关联的值,例如 (get votes [:Id :CreationDate])
。我尝试了很多事情,其中大部分都会导致铸造错误。
最接近我需要的是使用 (doall (map get votes [:Id :CreationDate]))
。但是,我现在遇到的问题是我似乎不能 return 除了第一行(即 (1 2011-01-19T00:00:00.000)
)
这是一个可以在任何 Clojure REPL 上 运行 或 on Codepad online IDE 的 MCVE。
理想情况下,我想要 return 某种包含我需要的每一行值的集合或地图,最终目标是写入 CSV 文件等文件。例如像
这样的地图
(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)
(def votes '({:Id "1",
:PostId "2",
:VoteTypeId "2",
:CreationDate "2011-01-19T00:00:00.000"}
{:Id "2",
:PostId "3",
:VoteTypeId "2",
:CreationDate "2011-01-19T00:00:00.000"}
{:Id "3",
:PostId "1",
:VoteTypeId "2",
:CreationDate "2011-01-19T00:00:00.000"}
{:Id "4",
:PostId "1",
:VoteTypeId "2",
:CreationDate "2011-01-19T00:00:00.000"}))
(println (doall (map get votes [:Id :CreationDate])))
其他详细信息:如果这是任何 help/interest,我用来获取上述惰性序列的代码如下:
(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)
你显然需要 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"}
首先,让我解释一下,您在 CodePad 中建议的这段代码实际上在做什么。我怀疑这是你打算做的事情:
(println (doall (map get votes [:Id :CreationDate])))
关键部分是:(map get votes [:Id :CreationDate])
这映射了两个集合:惰性序列 'votes' 和一个向量。每当映射超过一个集合时,返回的惰性序列将与提供的最短集合一样长。
例如,可以映射有限集合和无限序列:
(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))
最终减少到:
(1 2011-01-19T00:00:00.000)
这只是为了理解目的。如果编译器确实执行了这些步骤,那就是另一个问题了。
doall
在这里不是必需的,因为 println
已经隐含地这样做了。
如前所述。在您的情况下,您最好使用 juxt
并且只映射选票。如果你真的想要样本输出,你还需要展平输出:
(flatten (map (juxt :Id :CreationDate) votes))
我正在使用 clojure.data.xml
解析来自 Stack Exchange 的一些 XML 数据,例如,如果我解析 Votes 数据,它 return 是一个包含每行数据的 HashMap 的 LazySeq。
我想做的是为每一行获取仅与某些键关联的值,例如 (get votes [:Id :CreationDate])
。我尝试了很多事情,其中大部分都会导致铸造错误。
最接近我需要的是使用 (doall (map get votes [:Id :CreationDate]))
。但是,我现在遇到的问题是我似乎不能 return 除了第一行(即 (1 2011-01-19T00:00:00.000)
)
这是一个可以在任何 Clojure REPL 上 运行 或 on Codepad online IDE 的 MCVE。
理想情况下,我想要 return 某种包含我需要的每一行值的集合或地图,最终目标是写入 CSV 文件等文件。例如像
这样的地图(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)
(def votes '({:Id "1",
:PostId "2",
:VoteTypeId "2",
:CreationDate "2011-01-19T00:00:00.000"}
{:Id "2",
:PostId "3",
:VoteTypeId "2",
:CreationDate "2011-01-19T00:00:00.000"}
{:Id "3",
:PostId "1",
:VoteTypeId "2",
:CreationDate "2011-01-19T00:00:00.000"}
{:Id "4",
:PostId "1",
:VoteTypeId "2",
:CreationDate "2011-01-19T00:00:00.000"}))
(println (doall (map get votes [:Id :CreationDate])))
其他详细信息:如果这是任何 help/interest,我用来获取上述惰性序列的代码如下:
(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)
你显然需要 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"}
首先,让我解释一下,您在 CodePad 中建议的这段代码实际上在做什么。我怀疑这是你打算做的事情:
(println (doall (map get votes [:Id :CreationDate])))
关键部分是:(map get votes [:Id :CreationDate])
这映射了两个集合:惰性序列 'votes' 和一个向量。每当映射超过一个集合时,返回的惰性序列将与提供的最短集合一样长。
例如,可以映射有限集合和无限序列:
(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))
最终减少到:
(1 2011-01-19T00:00:00.000)
这只是为了理解目的。如果编译器确实执行了这些步骤,那就是另一个问题了。
doall
在这里不是必需的,因为 println
已经隐含地这样做了。
如前所述。在您的情况下,您最好使用 juxt
并且只映射选票。如果你真的想要样本输出,你还需要展平输出:
(flatten (map (juxt :Id :CreationDate) votes))