(concat [x] y)和(cons x y)之间的区别是什么?

时间:2014-03-09 13:06:55

标签: clojure

我被困在4Clojure网站的Pascal's Trapezoid,你需要建立一个懒惰的数字序列。

我的第一枪就是:

(defn pascal [x]
  (cons x
   (lazy-seq
    (pascal 
     (map +
        (cons 0 x)
        (conj x 0)      
      )))))

哪个不起作用:

user=> (take 5 (pascal [1 1]))
([1 1] (1 2 1) (0 2 4 2) (0 0 4 8 4) (0 0 0 8 16 8))
然而,

以这种方式编写它是有效的:

(defn pascal2 [x]
  (cons x
   (lazy-seq
    (pascal2
     (map +
        (concat [0] x)
        (concat x [0])      
      )))))

user=> (take 5 (pascal2 [1 1]))
([1 1] (1 2 1) (1 3 3 1) (1 4 6 4 1) (1 5 10 10 5 1))

那么,我到底做错了什么? cons / conj和concat有什么区别?

3 个答案:

答案 0 :(得分:3)

正如其他人所说,conj根据具体的集合类型将其收到的元素插入到不同的位置,请参阅this SO问题以获取有关{{1}之间差异的更多详细信息}和conj

cons函数的第一个版本中,您提供了一个向量作为初始参数,因此表达式pascal将在向量的末尾插入(conj x 0)以进行计算系列中的第二个元素但是,因为map返回一个惰性序列,当计算第三个元素时,插入发生在开头(0),这导致系列中的元素错误从那以后。

要使用(conj (map inc '(0)) 2) ;= (2 1)cons方法,您必须确保使用conj而不是mapv返回向量。

map

(defn pascal [x] (cons x (lazy-seq (pascal (mapv + (cons 0 x) (conj x 0)))))) (take 5 (pascal [1 1])) ;= ([1 1] [1 2 1] [1 3 3 1] [1 4 6 4 1] [1 5 10 10 5 1]) 的缺点是它非常渴望它会计算pascal元素中的所有成员,而不是仅仅在实际需要它之前将其保留。

另一方面,当你使用mapv时,确保你将元素追加到最后,并且所有内容都是懒惰的,但附加信息并不像向量那样便宜,请参阅here了解更多信息信息。

无论这些因素如何,您仍然可以在两种情况下都使用concat,因为它的作用就是您在任何一种情况下所需要的(即在集合的开头插入一个元素)。

cons

答案 1 :(得分:2)

根据ClojureDocs

conj clojure.core

(conj coll x)
(conj coll x & xs)
  

缀[OIN]。返回xs'已添加'的新集合。 (没法   item)返回(item)。 “添加”可能发生在不同的“地方”   取决于具体类型。

conj接受第一个参数作为集合,这意味着coll必须是集合类型。 conj会将x添加到coll中的新集合返回,添加x的地点取决于coll的类型。

e.g。

> (conj [1] [0])
 [1 [0]] ; See [0] is added into [1] as an element. Instead of returning [1 0], it returns [1 [0]]
> (conj [1] 0)
 [1 0]
> (conj '(1) 0)
 (0 1) ;See the element `0` position is different in each case.

的concat

concat clojure.core
(concat)
(concat x)
(concat x y)
(concat x y & zs)
  

返回表示元素串联的惰性seq   提供的歌词。

concat接受所有参数作为集合类型,这与conj不同。 concat返回参数的连接。

e.g。

> (concat [0] [1])
(0 1)
> (concat [0] [[1]])
(0 [1])
> (concat [0] 1) ;See the second argument is not a collection type, thus the function throws an exception.
java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long
>  

缺点

cons clojure.core 
(cons x seq)
  

返回一个新的seq,其中x是第一个元素,seq是其余元素。

cons的文件清楚地说明cons将如何运作。 cons的第二个参数必须是seq

e.g。

> (cons [1] [0])
([1] 0) ; [1] is the first element and (0) is the rest
> (first (cons [1] [0]))
[1]
> (rest (cons [1] [0]))
(0)
> (cons 1 [0]) ; 1 is the first element and (0) is the rest
(1 0)
> (cons [1] 0) ;the second argument is not a seq, throwing exception
java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long

答案 2 :(得分:2)

conj上的

list会将元素添加到列表的前面。 如果将列表转换为矢量,它将起作用。

user=> (conj '(1 2 3) 4)
(4 1 2 3)
user=> (conj [1 2 3] 4)
[1 2 3 4]