gpt4 book ai didi

json - 在 clojure 中使用嵌套映射/向量结构的惯用且简洁的方式

转载 作者:行者123 更新时间:2023-12-01 06:51:07 24 4
gpt4 key购买 nike

我是 clojure 的新手,作为学习语言的练习,我正在用 clojure 重写我的一个旧的 groovy 脚本。对于上下文,脚本查询 JIRA 实例以获取时间条目,接收 json 格式的结果并根据响应生成报告。

我意识到已经在 s.o. 上无穷无尽地询问了有关遍历嵌套结构的问题,但我未能找到直接答案,因此我希望 clojurists 以惯用和简洁的方式提供一些帮助。核心问题是通用的,与这段特定的代码无关。

我希望在 clojure 中重写以下内容:

// GROOVY CODE
// this part is just here for context
def timeFormat = DateTimeFormat.forPattern('yyyy/MM/dd')
def fromDate = timeFormat.parseDateTime(opts.f)
def toDate = timeFormat.parseDateTime(opts.t)

def json = queryJiraForEntries(opts, http)
def timesheets = [:].withDefault { new TimeSheet() }

// this is what I'm hoping to find a better way for
json.issues.each { issue ->
issue.changelog.histories.each { history ->
def date = DateTime.parse(history.created)
if (date < fromDate || date > toDate) return

def timeItems = history.items.findAll { it.field == 'timespent' }
if (!timeItems) return

def consultant = history.author.displayName
timeItems.each { item ->
def from = (item.from ?: 0) as Integer
def to = (item.to ?: 0) as Integer

timesheets[consultant].entries << new TimeEntry(date: date, issueKey: issue.key, secondsSpent: to - from)
}
}
}

(返回的json的示例结构可以在 here中找到)

请注意,当我们创建结果时间条目时,我们使用 issue.key从最外层, date从中级开始,和 fromto从嵌套结构的最内层。

在 groovy 中,一个 returneach循环只存在于最里面的每一个。我相信其余的代码应该或多或少是不言自明的。

所以我试图解决的一般问题是:给定一个深度嵌套的 map 和列表结构:
  • 遍历/过滤到结构的特定深度
  • 对该深度级别的数据执行一些操作并将结果添加到上下文
  • 遍历/过滤更深的结构
  • 对该深度级别的数据执行一些操作并将结果添加到上下文
  • ...
  • 在某个最终级别,根据上下文中的数据和该级别可用的数据生成结果。

  • 我发现这种上下文遍历和数据转换是一种越来越常见的模式。

    我目前的解决方案比 groovy 的解决方案更冗长,而且对于我未经训练的阅读 clojure 代码的眼睛来说,一目了然更难理解。解析日期等的细节并不重要。我正在寻找的是一个简洁的 clojure 模式。

    编辑 1:每个评论中的请求,这是我当前的代码。我提前道歉并无耻地将这一切归咎于我的新手:
    ;; CLOJURE CODE
    (defn valid-time-item? [item]
    (and (= (:field item) "timespent") (:to item) (:from item)))

    (defn history->time-items [history]
    (filter valid-time-item? (:items history)))

    (defn history-has-time-items? [history]
    (not-empty (history->time-items history)))

    (defn history-in-date-range? [opts history]
    (tcore/within? (tcore/interval (:from-date opts) (:to-date opts))
    (tformat/parse (tformat/formatters :date-time) (:created history))))

    (defn valid-history? [opts h]
    (and (history-has-time-items? h) (history-in-date-range? opts h)))

    (defn issue->histories-with-key [issue]
    (map #(assoc % :issue-key (:key issue))(get-in issue [:changelog :histories])))

    (defn json->histories [opts json]
    (filter #(valid-history? opts %) (flatten (map issue->histories-with-key (:issues json)))))

    (defn time-item->time-entry [item date issue-key]
    (let [get-int (fn [k] (Integer/parseInt (get item k 0)))]
    {:date (tformat/unparse date-formatter date)
    :issue-key issue-key
    :seconds-spent (- (get-int :to) (get-int :from)) }))

    (defn history->time-entries [opts history]
    (let [date (tformat/parse (tformat/formatters :date-time) (:created history))
    key (:issue-key history)]
    (map #(time-item->time-entry % date key) (history->time-items history))))

    (defn json->time-entries [opts json]
    (flatten (map #(history->time-entries opts %) (json->histories opts json))))

    (defn generate-time-report [opts]
    (json->time-entries opts (query-jira->json opts)))

    为简洁起见,省略了一些脚手架等。上面的入口点是 generate-time-report它返回一组 map 。

    issue->histories-with-key我保留了 issue.key通过将问题键粘贴到每个历史 map 中来实现上下文。除了代码的一般结构之外,这是我觉得丑陋且不可扩展的要点之一。另外我还没有添加 consultant clojure 解决方案的维度。

    编辑 2:在从评论和下面的答案中进行一些摆弄和输入之后,第二次尝试。这个有点短,使用更接近原始代码的结构,并具有 consultant原始代码中的一段包括:
    ;; CLOJURE CODE - ATTEMPT 2
    (defn create-time-entry [item date consultant issue-key]
    (let [get-int #(Integer/parseInt (or (% item) "0"))]
    {:date (f/unparse date-formatter date)
    :issue-key issue-key
    :consultant consultant
    :seconds-spent (- (get-int :to) (get-int :from)) }))

    (defn history->time-entries [history issue-key from-date to-date]
    (let [date (f/parse (f/formatters :date-time) (:created history))
    items (filter #(= (:field %) "timespent") (:items history))
    consultant (get-in history [:author :displayName])]
    (when (and (t/within? (t/interval from-date to-date) date) (not-empty items))
    (map #(create-time-entry % date consultant issue-key) items))))

    (defn issue->time-entries [issue from-date to-date]
    (mapcat #(history->time-entries % (:key issue) from-date to-date)
    (get-in issue [:changelog :histories])))

    (defn json->time-entries [json from-date to-date]
    (mapcat #(issue->time-entries % from-date to-date) (:issues json)))

    (defn generate-time-report [opts]
    (let [{:keys [from-date to-date]} opts]
    (filter not-empty
    (json->time-entries (query-jira->json opts) from-date to-date))))

    最佳答案

    我认为您的 Clojure 代码一点也不差。这就是我将如何改进它。只是一些变化。

    (defn valid-time-item? [item]
    (and (= (:field item) "timespent") (:to item) (:from item)))

    (defn history->time-items [history]
    (filter valid-time-item? (:items history)))

    (defn history-has-time-items? [history]
    (not-empty (history->time-items history)))

    (defn history-in-date-range? [history from-date to-date]
    (tcore/within? (tcore/interval from-date to-date)
    (tformat/parse (tformat/formatters :date-time) (:created history))))

    (defn valid-history? [h from-date to-date]
    (and (history-has-time-items? h) (history-in-date-range? h from-date to-date)))

    (defn issue->histories-with-key [issue]
    (map #(assoc % :issue-key (:key issue)) (get-in issue [:changelog :histories])))

    (defn time-item->time-entry [item date issue-key]
    (let [get-int (fn [k] (Integer/parseInt (get item k 0)))]
    {:date date
    :issue-key issue-key
    :seconds-spent (- (get-int :to) (get-int :from))}))

    (defn history->time-entries [history]
    (map #(time-item->time-entry % (:created history) (:issue-key history)) (history->time-items history)))

    (defn json->time-entries [json opts]
    (let [{:keys [from-date to-date]} opts]
    (->> json
    :issues
    (mapcat issue->histories-with-key)
    (filter #(valid-history? % from-date to-date))
    (mapcat #(history->time-entries %)))))

    (defn generate-time-report [opts]
    (json->time-entries opts (query-jira->json opts)))

    主要变化
  • 未嵌套 json->time-entries执行。现在很清楚了 json变成 time-entries .例如。 json -> 问题 -> 历史 -> 时间输入
  • 使用 mapcat而不是 (flatten (map ...
  • 解构 :from-date:to-date早些时候。我想发送 from-dateto-date into 函数使函数签名比 opts 更具可读性
  • 的交换位置主题 ( json ) 和 opts .将最重要的参数放在第一个位置,除非它是像 map 这样接受 lambda 的集合函数, filter
  • 关于json - 在 clojure 中使用嵌套映射/向量结构的惯用且简洁的方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42551765/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com