2016-05-08 3 views
0

Мне интересно, как удалить повторяющиеся элементы из двух последовательностей и объединить две последовательности. Например,Удалить дубликаты элементов из двух последовательностей

user=>(remove-dup [1 4 7 10 16] [2 7 18 4]) 
(1 2 10 18 16) 

Мой код:

(defn remove-dup [l1 l2] 
    (let [list (concat l1 l2)] 
    (loop [l list res '()] 
     (if (>= (second (first (frequencies l))) 2) 
      (recur (rest l) res) 
      (recur (rest l) (conj res (first (first l)))))))) 

Но когда я запускаю код, я получил сообщение об ошибке:

IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:528) 

Как я могу исправить этот код. Благодаря!

+0

Важен ли заказ? –

+0

Порядок не важен. –

ответ

5

Ваша ошибка здесь:

(first (first l)) 

Помните, что l является последовательность всех элементов, которые вы еще не обработаны. Например, в первой итерации loop, l может выглядеть следующим образом:

(1 4 7 10 16 2 7 18 4) 

Вы можете видеть из этого, что (first l) будет 1, так (first (first l)) будет пытаться лечить ряд как последовательность, которая Безразлично Не работай.

Если заменить (first (first l)) только с (first l), вы получите NullPointerException, потому что вы не имеете базовый случай: то, что вы должны делать, когда l пуст? Вы могли бы сделать что-то вроде этого (где ,,, является заполнителем для текущего if выражения):

(if (empty? l) 
    res 
    ,,,) 

Однако, если мы попытаемся использовать метод сейчас, мы до сих пор не получить правильный результат:

(remove-dup [1 4 7 10 16] [2 7 18 4]) 
;=> (4 18 7 2 16 10 1) 

Hrm.

Я мог бы попытаться сыграть с вашим кодом еще немного, чтобы заставить его работать, но есть лучший способ решить эту проблему. Поскольку вы пытаетесь удалить дубликаты и вам не нужен порядок, функции в clojure.set являются подходящим инструментом для работы здесь. Я хотел бы написать remove-dup так:

(require '[clojure.set :as set]) 

(defn remove-dup [c1 c2] 
    (let [[s1 s2] (map set [c1 c2])] 
    (seq (set/difference (set/union s1 s2) (set/intersection s1 s2))))) 

Пример:

(remove-dup [1 4 7 10 16] [2 7 18 4]) 
;=> (1 2 16 10 18) 
+0

Спасибо! Теперь я знаю, в чем моя проблема. –

2

существует целый ряд фатальных ошибок в вашем коде:

Дело в том, что разрушает его, является (first (first l)), поскольку l является список чисел, он выдает ошибку при попытке взять первый элемент номера.

Но есть более важные из них:

первой очереди, даже если ваш код был правильным, он не имеет ни одного случая, чтобы разорвать петлю, так что, вероятно, приведет к бесконечному циклу (или исключения). Во-вторых, ваше полное непонимание использования frequencies. Вы не можете рассчитывать на порядок результатов frequencies, так как он возвращает неупорядоченную карту (не говоря уже о том, что она вызывается в каждой итерации цикла, что очень плохо для предварительной работы).

Вот как я хотел бы сделать что-то вроде этого один проход по коллекции в цикле:

(defn unique [coll1 coll2] 
    (let [items (concat coll1 coll2)] 
    (loop [res #{} 
      seen #{} 
      [x & xs :as items] items] 
     (cond ;; if there are no items left to check, returning result 
      (empty? items) res 
      ;; if we've already seen the first item of a coll, remove it from the resulting set 
      (seen x) (recur (disj res x) seen xs) 
      ;; otherwise mark it as seen, and add it to the result set 
      :else (recur (conj res x) (conj seen x) xs))))) 

в РЕПЛ:

user> (unique [1 4 7 10 16] [2 7 18 4]) 
#{1 2 16 10 18} 
0
(defn remove-dupl [l1 l2] 
    (let [rmdup (fn [l1 l2] (remove (set l1) l2))] 
    (concat (rmdup l1 l2) (rmdup l2 l1)))) 
0

Попробуйте это решение

(defn remove-dup [l1 l2] 
    (let [ls (concat l1 l2)] 
    (loop [l (frequencies ls) res '()] 
     (if (empty? l) res 
      (if (>= (second (first l)) 2) 
       (recur (rest l) res) 
       (recur (rest l) (cons (first (first l)) res))))))) 
0

Другие обнаружили ваши ошибки. Я хотел бы посмотреть, что вы пытаетесь сделать.

Учитывая, что

  • порядок не важен и
  • вы удаляете повторяющихся элементов

это множественная операцияexclusive or (XOR).

Он не включен в clojure.set. Мы можем или, как Sam Estep делает, определить в терминах операций мы имеем, или записать его более непосредственно сами:

(defn exclusive-or [sa sb] 
    (if (<= (count sa) (count sb)) 
    (reduce 
    (fn [ans a] 
     (if (contains? sb a) 
     (disj ans a) 
     (conj ans a))) 
    sb 
    sa) 
    (recur sb sa))) 

Мы можем определить

(defn remove-dup [xs ys]dited 
    (exclusive-or (set xs) (set ys)) 

Например,

(remove-dup [1 4 7 10 16] [2 7 18 4]) ;#{1 2 10 16 18} 

Отредактировано исправление ошибки в exclusive-or.

Смежные вопросы