Clojure实现for循环的方法是什么?
在这个问题中,您将得到一个值V和一个唯一整数列表。您的工作是找到大小为4的不同子集的数量,这些子集的总和为V。列表中的每个元素只能使用一次。如果找不到这样的子集,则改为输出0 例如,如果整数是Clojure实现for循环的方法是什么?,clojure,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的方法是什么?我会使
[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的方法是什么?我会使用
Clojure.map.combinations/combinations
来获得所有的4元素子集,然后过滤出那些不等于V的子集。我会这样做:
(ns example.solve
(:require[clojure.math.combinations:as combo]))
(defn求解
[新南威尔士州]
(过滤器(组件(部分=v)
(部分还原+)
(组合/组合s/n)))
我在我的示例中使用,因为这是从列表中获取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))
有趣的是,这个问题允许(双重?)递归解决方案,它只涉及求和和和计数(而不实际生成子集)
如果您查看初始元素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
就直接回答这个问题而言,下面是如何使用索引和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.combinationals
的方法快70%左右,但速度是双递归解的两倍 非常好,只是为了说明答案:(解[3,4,5,6,7,8,9,10]430)((3,8,9,10)(4,7,9,10)(5,6,9,10)(5,7,8,10)(6,7,8,9))
@JamesSharp-Thanx!在我的答案中添加了你的例子。comp函数非常出色!谢谢。我重构了你的函数以返回实际的解决方案:很好!我喜欢您的重构具有相同的形状,但将+替换为concat,并在需要时构建列表。谢谢你的洞察力!如果我们知道这些数字都是正数,这也允许一些短路。@Yes。也许如果所有这些都是负面的。此外,<代码>(SEQ XS)< /代码>测试可以扩展为考虑<代码> LeN<代码>。组合数学
解决方案是理解IMHO最简单的方法,而这一方法似乎很快。