使用clojure返回一个元素和两个原始序列不相同的序列

使用clojure返回一个元素和两个原始序列不相同的序列,clojure,tail-recursion,Clojure,Tail Recursion,我有两个序列,可以是向量或列表。现在我想返回一个序列,其元素与这两个序列不相同 以下是一个例子: (removedupl [1 2 3 4] [2 4 5 6]) = [1 3 5 6] (removeddpl [] [1 2 3 4]) = [1 2 3 4] 我现在很困惑。这是我的代码: (defn remove-dupl [seq1 seq2] (loop [a seq1 b seq2] (if (not= (first a) (first b))

我有两个序列,可以是向量或列表。现在我想返回一个序列,其元素与这两个序列不相同

以下是一个例子:

(removedupl [1 2 3 4] [2 4 5 6]) = [1 3 5 6]
(removeddpl [] [1 2 3 4]) = [1 2 3 4]
我现在很困惑。这是我的代码:

(defn remove-dupl [seq1 seq2]
    (loop [a seq1 b seq2]
        (if (not= (first a) (first b))
            (recur a (rest b)))))

但我不知道下一步该怎么办。

我对Clojure还是新手,但我认为功能思维更倾向于编写函数,而不是“手工”编写,因此我提出以下解决方案:

(defn remove-dupl [seq1 seq2]
  (concat
    (remove #(some #{%} seq1) seq2)
    (remove #(some #{%} seq2) seq1)))
编辑:我认为最好将
删除
部分定义为一个本地函数并重用它:

(defn remove-dupl [seq1 seq2]
  (let [removing (fn [x y] (remove #(some #{%} x) y))]
    (concat (removing seq1 seq2) (removing seq2 seq1))))
编辑2:正如蒂莫西普拉特利所评论的那样

(defn remove-dupl [seq1 seq2]
  (let [removing (fn [x y] (remove (set x) y))]
    (concat (removing seq1 seq2) (removing seq2 seq1))))

我鼓励你们从集合运算的角度来考虑这个问题

(defn extrasection [& ss]
  (clojure.set/difference
    (apply clojure.set/union ss)
    (apply clojure.set/intersection ss)))
这种公式假设输入是集合

(extrasection #{1 2 3 4} #{2 4 5 6})
=> #{1 6 3 5}
通过对列表、序列或向量调用(set…)函数可以轻松实现


即使您更喜欢使用面向序列的解决方案,请记住,如果您扫描两个序列[除非它们已排序],搜索两个序列也是一项O(n*n)任务。集合可以在一次过程中构造,查找速度非常快。检查重复项是一项使用set的O(nlogn)任务。

您的代码有几个问题

  • 它不测试两个序列参数的结尾
  • 它通过
    b
    ,但不通过
    a
  • 当任意两个序列具有相同的值时,它隐式返回
    nil
    第一个要素

您希望从连接的序列中删除公共元素。您必须首先计算出公共元素,否则您不知道删除什么。所以

我们使用

  • clojure.set/intersection
    查找公共元素
  • concat
    将集合缝合在一起
  • remove
    从(2)中删除(1)
  • vec
    转换为向量
  • 因此

    。。。给

    (removedupl [1 2 3 4] [2 4 5 6]) ; [1 3 5 6]
    (removedupl [] [1 2 3 4]) ; [1 2 3 4]
    

    。。。根据需要

    对!!使用let后,阅读代码更容易。由于我是新学员,请您详细解释一下这句话(删除#(some#{%}x)y)。我查阅了参考资料,但对此我一无所知。非常感谢你!(remove(set seq1)seq2)比O(n^2)更快O(nlogn)而不是O(n^2)@Timothyprattley感谢您的更正,将进行更新。@xuifenxu Check@xuifenxu关于#()符号,请检查好的。我在查看交叉点,但记不起它的名称。如果两个输入序列都像示例中那样排序,则可以在O(n)时间内完成,而不需要集合。否则,集合就是方法。输入总是像示例中那样排序,还是只是巧合?
    (removedupl [1 2 3 4] [2 4 5 6]) ; [1 3 5 6]
    (removedupl [] [1 2 3 4]) ; [1 2 3 4]