实现for循环的Clojure方法是什么?

时间:2014-11-27 13:49:31

标签: clojure

在这个问题中,您将获得一个值V和一个唯一整数列表。您的工作是找到大小为4的不同子集的数量,总计为V.列表中的每个元素只能使用一次。如果找不到这样的子集,则输出0。

例如,如果整数为[3, 4, 5, 6, 7, 8, 9, 10]且值为30,则输出应为5.子集为:

[3, 8, 9, 10]
[4, 7, 9, 10]
[5, 6, 9, 10]
[5, 7, 8, 10]
[6, 7, 8, 9].

解决这个问题并不难,最直接的方法是将for循环嵌套四次。 Clojure的做法是什么?

4 个答案:

答案 0 :(得分:5)

我将如何做到这一点:

(ns example.solve
  (:require [clojure.math.combinatorics :as combo]))

(defn solve
  [s n v]
  (filter (comp (partial = v)
                (partial reduce +))
          (combo/combinations s n)))

我在我的示例中使用math.combinatorics,因为这是从列表中获取4个元素的所有组合的最简单方法。

以下是使用solve

的示例
=> (solve [3 4 5 6 7 8 9 10] 4 30)
((3 8 9 10) (4 7 9 10) (5 6 9 10) (5 7 8 10) (6 7 8 9))

答案 1 :(得分:3)

我会使用clojure.map.combinatorics/combinations来获取所有4个元素的子集,然后使用filter来获取那些不总和为V的子集。

答案 2 :(得分:3)

有趣的是,这个问题承认了一个(双重?)递归解决方案,它只涉及求和和计数(没有实际生成子集。)

如果你看一下初始元素3,那么解的一部分是从序列的其余部分中的3个元素中得到的和的数量,其中总和是27,这是相同问题的较小形式,因此可以以递归方式解决。递归的底部是当您查找从1个元素生成的总和时,归结为简单检查以查看所需的总和是否在列表中。

解决方案的另一部分涉及查看下一个元素4,在列表的其余部分中查找超过4等于26的总和,依此类推......此部分也可以递归处理。

将它作为递归函数放在一起如下所示,它为示例序列生成所需的答案5。

(defn solve [xs n len]
  (if (seq xs)
    (if (= len 1)
       (if (some #{n} xs) 1 0)
       (+ (solve (rest xs)
                 (- n (first xs))
                 (dec len))
          (solve (rest xs) 
                 n
                 len)))
    0))

(solve [3 4 5 6 7 8 9 10] 30 4)               
;=> 5

答案 3 :(得分:1)

就直接回答问题而言,以下是使用索引和for循环的方法:

(defn solve-for [xs v]
  (for [ndx0 (range 0          (- (count xs) 3))
        ndx1 (range (inc ndx0) (- (count xs) 2))
        ndx2 (range (inc ndx1) (- (count xs) 1))
        ndx3 (range (inc ndx2) (count xs))
        :when (= v (+ (xs ndx0) (xs ndx1) (xs ndx2) (xs ndx3)))]
    (list (xs ndx0) (xs ndx1) (xs ndx2) (xs ndx3))))

FWIW,这比使用clojure.math.combinatorics的方法快约70%,但是比双递归解决方案慢两倍。