我有以下数据:
({:seriesId "series 0", :episodeId "0"}
{:seriesId "series 1", :episodeId "1"}
{:seriesId "series 1", :episodeId "2"}
{:seriesId "series 2", :episodeId "3"}
{:seriesId "series 2", :episodeId "4"}
{:seriesId "series 2", :episodeId "5"})
并希望将每集与其系列相关联,如下所示:
[{:put-request
{:item {:seriesId "series 0", :episodeCount 1, :episodeIds #{"0"}}}}
{:put-request
{:item {:seriesId "series 1", :episodeCount 2, :episodeIds #{"1" "2"}}}}
{:put-request
{:item {:seriesId "series 2", :episodeCount 3, :episodeIds #{"3" "4" "5"}}}}]
目前我遇到以下情况:
[{:put-request
{:item {:seriesId "series 0", :episodeCount 1, :episodeIds #{"0"}}}}
{:put-request
{:item {:seriesId "series 1", :episodeCount 1, :episodeIds #{"1"}}}}
{:put-request
{:item {:seriesId "series 1", :episodeCount 1, :episodeIds #{"2"}}}}
{:put-request
{:item {:seriesId "series 2", :episodeCount 1, :episodeIds #{"3"}}}}
{:put-request
{:item {:seriesId "series 2", :episodeCount 1, :episodeIds #{"4"}}}}
{:put-request
{:item {:seriesId "series 2", :episodeCount 1, :episodeIds #{"5"}}}}]
我正在使用create-or-update-series
功能。我不知道如何使用seriesId
查找/获取以前添加的系列(如果已添加!)。我尝试了很多东西,但这些都是死路一条。
(ns clojure-sscce.core
(:gen-class)
(:require clojure.pprint))
(defn create-or-update-series
([episodes]
(create-or-update-series episodes []))
([episodes result]
(if (zero? (count episodes))
result
(create-or-update-series (rest episodes)
(conj result {
:put-request {
:item {
:seriesId (:seriesId (first episodes))
:episodeCount 1
:episodeIds #{(:episodeId (first episodes))}}}})))))
;; Tests
(defn -main [& args]
(let
[series0 (mapv (fn [episode-id] {
:seriesId "series 0"
:episodeId (str episode-id)}) (range 0 1))
series1 (mapv (fn [episode-id] {
:seriesId "series 1"
:episodeId (str episode-id)}) (range 1 3))
series2 (mapv (fn [episode-id] {
:seriesId "series 2"
:episodeId (str episode-id)}) (range 3 6))]
(clojure.pprint/pprint
(concat series0 series1 series2))
(clojure.pprint/pprint
(create-or-update-series (concat series0 series1 series2)))))
请注意,{:put-request {:item { ...
是必需的,因为新地图应该是PUT到DynamoDB。
非常乐意帮助你!
答案 0 :(得分:5)
group-by
非常适合这样的事情。这是尝试与for
理解相结合的尝试:
(defn group-by-series [episodes]
(let [grouped (group-by :seriesId episodes)]
(for [[series eps-in-series] grouped]
{:seriesId series
:episodeCount (count eps-in-series)
:episodeIds (into #{} (map :episodeId eps-in-series))})))
(group-by-series example-data)
;=> ({:seriesId "series 0", :episodeCount 1, :episodeIds #{"0"}}
; {:seriesId "series 1", :episodeCount 2, :episodeIds #{"1" "2"}}
; {:seriesId "series 2", :episodeCount 3, :episodeIds #{"3" "4" "5"}})
如果需要,您可以在for
理解中添加DynamoDB内容,或者创建包装函数并将其映射到它们之间。
答案 1 :(得分:1)
因此,如果我们想要查看“创建或更新”问题,我们可以通过几种方式来实现它。就像你的尝试一样,我们需要递归地创建一系列的系列,但是像group-by
一样,最好将它设为 map ,以系列ID为基础。这样,当我们在输入中找到新的剧集时,我们可以轻松有效地找到它在集合中所属的系列。
首先,让我们做一些便利功能,只为一集更新这样的地图。它应该:
这是我的方法:
(defn- update-series-map [series-map {:keys [seriesId episodeId] :as episode}]
(let[current-series (get series-map seriesId
{:seriesId seriesId :episodeIds #{} :episodeCount 0})
updated-series (-> current-series
(update-in [:episodeCount] inc)
(update-in [:episodeIds] conj episodeId))]
(assoc series-map seriesId updated-series)))
如果系列还没有条目,我们可以使用get
的 if-not-found 参数创建一个合适的空系列,否则我们得到的条目是那里。在任何一种情况下,我们都必须更新条目以添加剧集 - 我们必须conj
剧集ID进入剧集集并inc
剧集计数。我使用update-in
来完成这两项工作,但是如果您使用的是Clojure 1.7 + update
则更适合这样的情况,我们不会使用比1键更深的键序列。
通过这个构建块,我们可以制作一些内容来循环播放几集。我们可以使用像create-or-update-series
:
(defn group-by-series-multiarity
([episodes]
(group-by-series-multiarity {} episodes))
([series-map
[ep & more]]
(if (seq more)
(recur (update-series-map series-map ep) more)
(vals (update-series-map series-map ep)))))
在结构上这基本相同。我使用recur
而不是通过名称重复主要作为优化。显式调用会占用调用堆栈空间,而recur
可以避免这种情况。使用seq
检查空虚是另一个小优化,因为我们不必遍历剩余的剧集来计算它们。
最后它需要一点清理,因为我们不想要我们创建的整个地图,只需要值。这就是我最后vals
的原因。
或者,我们可以使用loop
作为recur
的目标。如果我们的“公共API”不适合我们递归的方式,这可能会很好:
(defn group-by-series-looping[episodes]
(loop[series-map {}
[ep & more] episodes]
(if (seq more)
(recur (update-series-map series-map ep) more)
(vals (update-series-map series-map ep)))))
loop
基本上就像创建本地帮助函数(在本例中为arity 2)并在其中使用recur
一样。
我们还可以注意到这些递归函数遵循a well-known pattern called 'left fold' or 'reduction'并使用高阶函数抽象该模式:
(defn group-by-series-reducing [episodes]
(vals (reduce update-series-map {} episodes)))
请注意reduce
如果我们只提供它应该使用的缩减功能,loop
基本上会处理整个group-by-series-looping
update-series-map
{}
{{1}} })和初始值{{1}}。