Clojure возвращает список всех пар в seq, первым элементом которых является ключ.

Мне нужно определить функцию с именем (последовательность ключей для всех пар)

Он возвращает список всех пар в seq, первым элементом которых является ключ. Если нет совпадений, возвращается пустой список.

Например, если я определяю домашних животных

(def pets
   '((cat 1) (dog 1) (fish 1) (cat 2) (fish 2))
)

(get-all-pairs 'cat pets) возвращает ((cat 1) (cat 2)), а (get-all-pairs 'bird pets) возвращает '().

Вот моя попытка:

(defn get-all-pairs [key seq]
  (cond
    (= key (first(first(seq)))) (cons (first seq) 
                                      (get-all-pairs key (rest seq)))
    :else '()))

Но это не работает. Если я позвоню ему, он выведет следующие сообщения:

#'proj2.proj2/pets
=> (get-all-pairs 'cat pets)
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn  proj2.proj2/get-all-pairs (proj2.clj:20)

Я не знаю, где проблема. Как это исправить?


person MicM    schedule 08.03.2014    source источник


Ответы (2)


Непосредственная ошибка заключается в том, что в вашем определении слишком много скобок: (first (first (seq))) должно быть просто (first (first seq)). Как только вы это исправите, ваша функция должна завершиться, но дать вам неправильный ответ: подумайте, действительно ли () является тем, что вам нужно в вашем случае else.

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

(defn get-all-pairs [k pairs]
  (filter #(= k (first %)) pairs))
person amalloy    schedule 08.03.2014
comment
Большое спасибо! Прочитав ваш комментарий, я понимаю, что мой случай :else неверен. Но теперь я столкнулся с новой проблемой. Если я попытаюсь: (cond (= key (first(first seq))) (cons (first seq) (get-all-pairs key (rest seq))) (not= key (first (first seq))) (get -all-pairs key (rest seq)) :else '() ) Оказывается, это сообщение об ошибке переполнения стека. Как я могу закончить этот рекурсивный подход? - person MicM; 08.03.2014
comment
Что ж, если вы посмотрите повнимательнее, то увидите, что на самом деле у вас вообще нет базового случая: либо первый ключ равен key, и в этом случае вы повторяетесь, либо нет, и в этом случае вы все еще повторяетесь; у вас есть предложение :else, но оно работает только в том случае, если x не равно ни key, ни не равно ему (т. е. никогда). - person amalloy; 08.03.2014

Вы на правильном пути, но как-то слишком много думаете об этом. For позволяет абстрагироваться от многих вещей, которые вы пытаетесь сделать вручную. В этом случае мы можем сгенерировать последовательность и многократно использовать выражение if с :when.

(defn get-all-pairs [animal L]
  (for [k L
        :when (= animal (first k))]
    k))
person dizzystar    schedule 08.03.2014