首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何与clojure中很少使用的状态进行映射?

如何与clojure中很少使用的状态进行映射?
EN

Stack Overflow用户
提问于 2017-06-05 14:36:24
回答 5查看 177关注 0票数 3

情况如下:我正在转换一个值序列。每个值的转换分解为若干不同的情况。大多数价值观是完全相互独立的。然而,有一种特殊情况要求我跟踪到到目前为止我遇到了多少特殊情况。在命令式编程中,这非常简单:

代码语言:javascript
复制
int i = 0;
List<String> results = new ArrayList<>();
for (String value : values) {
  if (case1(value)) {
    results.add(handleCase1(value));
  } else if (case2(value)) {
  ...
  } else if (special(value)) {
    results.add(handleSpecial(value, i));
    i++;
  }
}

然而,在Clojure中,我想出的最好的方法是:

代码语言:javascript
复制
(first 
 (reduce 
  (fn [[results i] value]
      (cond
       (case-1? value) [(conj results (handle-case-1 value)) i]
       (case-2? value) ...
       (special? value) [(conj results (handle-special value i))
                         (inc i)]))
  [[] 0] values))

考虑到如果没有特例,这将变得非常丑陋:

代码语言:javascript
复制
(map #(cond 
       (case-1? %) (handle-case-1 %)
       (case-2? %) ...)
      values)

问题是,在还原过程中,我正在手工拼接一个序列。而且,大多数情况下甚至都不关心指数,但仍必须在下一个缩减步骤中传递它。

这个问题有更干净的解决办法吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2017-06-05 16:06:02

有时,使用looprecur的代码比使用reduce的等效代码要好。

代码语言:javascript
复制
(loop [[v & more :as vs] values, i 0, res []]
  (if-not (seq vs)
    res
    (cond
      (case-1? v) (recur more i (conj res (handle-case-1 v)))
      (case-2? v) (recur more i (conj res (handle-case-2 v)))
      (special? v) (recur more (inc i) (conj res (handle-special i v))))))

由于似乎有一些需求,这里有一个产生惰性序列的版本。关于过早优化和保持简单适用的习惯警告。

代码语言:javascript
复制
(let [handle (fn handle [[v & more :as vs] i]
               (when (seq vs)
                 (let [[ii res] (cond
                                 (case-1? v) [i (handle-case-1 v)]
                                 (case-2? v) [i (handle-case-2 v)]
                                 (special-case? v) [(inc i) (handle-special i v)])]
                   (cons res (lazy-seq (handle more ii))))))]
  (lazy-seq (handle values 0)))
票数 3
EN

Stack Overflow用户

发布于 2017-06-05 17:02:39

你想要一种纯功能的方法?尝试使用Map集合来满足临时值需求。这将使您的结果保持良好和干净,并在需要时方便地访问这些临时值。

当我们遇到一个特殊的值时,我们还会更新地图中的计数器以及结果列表。通过这种方式,我们可以在处理过程中使用reduce存储一些状态,但是在没有atom的情况下,保持一切都是纯功能的。

代码语言:javascript
复制
(def transformed-values
  (reduce
    (fn [{:keys [special-values-count] :as m} value]
      (cond
        (case-1 value) (update m :results conj (handle-case-1 value))
        (case-2 value) (update m :results conj (handle-case-2 value))
        ...
        (special-case? value) (-> m
                                  (update :results conj (handle-special value special-values-count))
                                  (update :special-values-count inc))
        :else m))
    {:results [] :special-values-count 0}
    your-list-of-string-values))

(:results transformed-values)
;=> ["value1" "Value2" "VALUE3" ...]

(:special-values-count transformed-values)
;=> 2
票数 3
EN

Stack Overflow用户

发布于 2017-06-05 14:44:36

您可以使用一个原子来跟踪它:

代码语言:javascript
复制
(def special-values-handled (atom 0))

(defn handle-cases [value]
  (cond
    (case-1? value) (handle-case-1 value)
    (case-2? value) ...
    (special? value) (do (swap! special-values-handled inc)
                         (handle-special @special-values-handled value))))

那你就可以

代码语言:javascript
复制
(map handle-cases values)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44371397

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档