我是Clojure的新手,我很难习惯用数据结构来实现基本操作。

在Clojure中实现以下代码的惯用方式是什么?

l = [...]
for i in range(len(l)):
  for j in range(i + 1, len(l)):
    print l[i], l[j]

最佳答案

最简单(但不是大多数FP风格)与您的示例几乎相同:

(let [v [1 2 3 4 5 6 7]]
  (doseq [i (range (count v))
          j (range (inc i) (count v))]
    (println (v i) (v j))))

这是产生所有这些对的更多功能变体(它不是基于长度或索引,而是基于尾部迭代):
(let [v [1 2 3 4 5 6 7]]
  (mapcat #(map (partial vector (first %)) (rest %))
          (take-while not-empty (iterate rest v))))

输出:
 ([1 2] [1 3] [1 4] [1 5] [1 6] [1 7] [2 3] [2 4]
  [2 5] [2 6] [2 7] [3 4] [3 5] [3 6] [3 7] [4 5]
  [4 6] [4 7] [5 6] [5 7] [6 7])

然后只需在doseq中使用这些对即可避免任何副作用:
(let [v [1 2 3 4 5 6 7]
      pairs (fn [items-seq]
              (mapcat #(map (partial vector (first %)) (rest %))
                      (take-while not-empty (iterate rest items-seq))))]
  (doseq [[i1 i2] (pairs v)] (println i1 i2)))

更新:跟随@ dg123的答案。很好,但是您可以使用doseqfor的功能(例如,解构和防护)来做得更好:
(let [v [1 2 3 4 5 6 7]]
  (doseq [[x & xs] (iterate rest v)
          :while xs
          y xs]
    (println "x:" x "y:" y)))

您遍历集合的尾部,但是请记住,iterate会产生无限的coll:
user> (take 10 (iterate rest [1 2 3 4 5 6 7]))
([1 2 3 4 5 6 7] (2 3 4 5 6 7) (3 4 5 6 7)
 (4 5 6 7) (5 6 7) (6 7) (7) () () ())

因此,您必须以某种方式对其进行限制,使其仅包括非空集合。
解构形式[x & xs]将参数拆分为第一个参数和其余参数的序列:
user> (let [[x & xs] [1 2 3 4 5 6]]
        (println x xs))
1 (2 3 4 5 6)
nil

当绑定(bind)的集合为空或具有单个元素时,xs将为nil:
user> (let [[x & xs] [1]]
        (println x xs))
1 nil
nil

因此,您只需在列表推导中使用:while保护器就可以使用此功能。

最后,您只需为xxs中的每个项目构造对(或在这种情况下产生一些副作用)

10-08 13:42