关于递归:Clojure-“ get”和“ nth”的混合?

Clojure - blend of “get” and “nth”?

我正在努力寻找一个可以在get函数和nth之间找到快乐的函数。 我已经对这些序列类型的函数进行了很多研究,是否有人知道解决此问题的方法,或者知道这样执行的函数?

我需要nth的能力来获取子列表:

1
2
3
4
=> (nth '(1 (2 3) 4 5) 1)
(2 3)
=> (get 1 '(1 (2 3) 4 5))
nil

而且我需要get能够在超出范围时返回" nil":

1
2
3
4
5
=> (get -1 '(1 (2 3) 4 5))
nil
=> (nth '(1 (2 3) 4 5) -1)
Execution error (IndexOutOfBoundsException) at user/eval149 (REPL:1).
null

我需要以下代码来实现递归子序列功能:

1
2
3
4
5
6
(defn sub-seq [coll i j]
  (nth coll i)
  (if (< i (+ i j))
    (sub-seq coll (inc' i) j)
  )
)

(sub-seq函数应该从位置" i"返回" j"个元素。)

这是我尝试编写的一些示例输出:

1
2
3
4
=> (sub-seq '(1 2 (3 4) (5 (6 7))) 1 2))
(2 (3 4))
=> (sub-seq '(1 2 3 4 5 6 7) 2 4)
(3 4 5 6)

我终于可以使用我的功能了,谢谢大家的帮助:

1
2
3
4
5
6
(defn sub-seq [coll i j]
  (conj
    (list*
      (nth coll i nil)
      (if (> j 1)
        (sub-seq coll (+ i 1) (- j 1))))))


nth采用可选的第三个参数not-found。如果索引超出范围,则可以使用它提供默认值:

1
2
3
4
5
user=> (nth '(1 (2 3) 4 5) -1)
Execution error (IndexOutOfBoundsException) at user/eval1 (REPL:1).
null
user=> (nth '(1 (2 3) 4 5) -1 nil)
nil

如果有矢量,则可以直接使用subvec

1
2
(let [s [1 2 3 4 5 6 7]]
  (subvec s 2 6))

如果有序列,则可以编写:

1
2
3
4
5
6
7
8
9
(defn subsequence [coll start n]
  (->> coll
       (drop start)
       (take n)))

(subsequence '(1 2 (3 4) (5 (6 7))) 1 2)
=> (2 (3 4))
(subsequence '(1 2 3 4 5 6 7) 2 4)
=> (3 4 5 6)

旁注:编写Clojure程序时,通常可以通过序列处理来更简单地解决问题。有时候递归算法是必要的,但通常您可以使用Clojure丰富的可对序列进行操作的函数集。


您误解了get。它适用于诸如地图和向量的关联集合。考虑:

1
2
3
4
5
6
7
8
9
10
11
(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(dotest
  (let [data-list '(1 (2 3) 4 5)
        data-vec (vec data-list) ]
    (spyx (nth data-list 1))
    (spyx (nth data-vec 1))
    (spyx (get data-list 1))
    (spyx (get data-vec 1))
    ))

结果

1
2
3
4
(nth data-list 1)  => (2 3)
(nth data-vec 1)   => (2 3)
(get data-list 1)  => nil
(get data-vec 1)   => (2 3)

由于Clojure列表不像地图那样具有关联性,因此list完全不应该与列表一起使用。理想情况下,get在传递列表参数以指示其不适用于它们时会引发异常。

对于您的特定目标,也许要做一些类似的事情:

1
2
(take j
  (drop i coll))

有关其他文档,请在此处查看。