【问题标题】:Clojure-How to add successive pairs in vector?Clojure-如何在向量中添加连续对?
【发布时间】:2014-12-16 02:06:57
【问题描述】:

尝试编写一个递归函数,将连续对添加到向量中。

[1 2 3 4] => [3 5 7]

几乎卡住了,这就是我目前所拥有的:

(def tmp  [ 1 2 3 4])

user> (map #(+ (second %) (first %)) (partition-all 2 tmp ))

这是错误的,因为它只添加了对而不是连续的对。我得到[3 7] 而不是[3 5 7]

【问题讨论】:

  • 根据我的经验,您最好编写自己的(总是递归的,如果我们包含 recurs)版本的标准库函数,而不是编写从头算起的问题解决方案标准函数在一行中解决。这里为您提供了两个这样的解决方案。

标签: vector clojure sum


【解决方案1】:

Partition 需要一个额外的参数来指定每个分区之间前进的距离。

(map #(apply + %) (partition 2 1 [1 2 3 4 5])) =>

(3 5 7 9)

【讨论】:

  • 如果我想使用递归,我该怎么做?
【解决方案2】:

这是另一种可能的解决方案:

(def tmp [1 2 3 4])

(map + tmp (rest tmp))

【讨论】:

    【解决方案3】:

    您要求的是递归函数,尽管在大多数情况下,集合和列表函数比制作自己的递归函数更可取,但这并不总是可行的。这个问题也很容易以惯用的函数方式递归编写,使用 accumulator

    这个想法是您从一个空的累加器开始,然后逐步构建您的结果。累加器(此代码 sn-p 中的 acc)将最终保存答案。

    (defn add-pairs [v1]
      (loop [the-list v1  acc []]
        (if   (next the-list) ;; checks wether there's more than 1 left in the-list
          (recur (rest the-list ) 
                 (conj  acc (+ (first the-list) (second the-list))))
         acc)))
    

    这里发生了什么?你将向量[1 2 3 4] 传递给v1。 然后循环开始并在其中初始化两个变量:

    the-list <- [1 2 3 4]
    acc []
    

    只需将前两个元素(+ (first the-list) (second the-list) 的总和添加到累加器中即可。然后使用recur 再次调用循环,传递列表的其余部分(rest the-list) 和累加器,现在持有3(作为前两个元素的总和)。新的价值是:

    the-list <- [2 3 4]
    acc [3]
    

    下一步:

    the-list <- [3 4]
    acc [3 5]
    
    the-list <- [4]
    acc [3 5 7]
    

    然后 if 条件不再成立并返回 else 子句(方便的是累加器,现在持有解决方案)。

    总体思路

    您从一个空的累加器和您的输入集开始。每一步,累加器都会累积。在大多数情况下,输入集也每一步都在变小。然后满足一些 if 条件并且累加器返回。

    在这个特定问题中也非常经典的是输入集在每一步都丢失了它的第一个元素。 (rest ) 在这里非常实用(大多数其他 lisps 中的 cdr )。

    一般形式

    clojure 中的循环/递归形式非常好,但在许多其他语言中,这种语法缺乏。一个非常经典的解决方案是具有两个函数:一个执行循环的递归函数,一个具有相同名称但另一个执行累加器初始化的 arity。代码比解释简单,所以这里是一些类似 java 的语法:

    function add-pairs(v1 acc) {
       if (cond)
          //do stuff to v1 and acc
          add-pairs(v1 acc)
       else 
          return acc }
    
    function add-pairs(v1) {
       return add-pairs(v1,[])
    }
    
    var result = add-pairs([42 666 1447]) 
    

    【讨论】:

    • 非常感谢您一步一步的解释。会玩这个更多。
    • 非常好的介绍 Clojure 中的递归。顺便说一句,使用count 检查某物是否为空是个坏主意。它与惰性集合的大小成线性关系——即使是以前计算过的集合(计数未缓存)。只需查看(empty? (next the-list)),便宜得多。
    • @noismith ,真的,我怀疑使用它,但我没有,因为它似乎只需要解释一步(因为 nil pinning 和真实性与更惯用的检查方式发挥作用)。但是,在示例中不使用正确的方式是一个坏主意。所以我会改变它。
    • 甚至(不是(下一个列表))?
    • 对于 stackoverflow 答案来说,这是一个不错的解决方案,但我永远不会用急切的循环/递归结构编写这个函数。在现实生活中,我只会使用 partition/map,但如果我想手动递归地执行此操作,lazy-seq 方法会更好,而且同样简单。
    猜你喜欢
    • 2022-01-04
    • 1970-01-01
    • 2016-10-04
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多