Обход списка Clojure (seq) для сравнения элементов с другими элементами - PullRequest
2 голосов
/ 23 июня 2011

Скажем, у меня есть список (abcde), я пытаюсь найти "ленивый" и идиоматический способ создания списка или последовательности каждого элемента с каждым другим элементом, например ((ab) (ac) (ad) (ae) (bc) (bd) (be) (cd) (ce) (de)).

Кажется, что Clojure for не позволяет этого, он просто производит один элемент, проходя через список и не разрешая доступ к подсписку.Самое близкое, что я до сих пор сделал - это превратил исходный список в вектор, и имел оператор for, который перебирает количество векторов и захватывает проиндексированные элементы,

(для [i (диапазон векторов-счетчиков) j (диапазон i-векторов-счетчиков)] ...

но я надеюсь, что есть лучший способ.

Ответы [ 3 ]

3 голосов
/ 23 июня 2011

FWIW, я пытался написать это, не глядя на код в contrib.Я думаю, что мой код намного проще для понимания, и в моем простом тесте он более чем в два раза быстрее.Он доступен по адресу https://gist.github.com/1042047, и воспроизведен ниже для удобства:

(defn combinations [n coll]
  (if (= 1 n)
    (map list coll)
    (lazy-seq
     (when-let [[head & tail] (seq coll)]
       (concat (for [x (combinations (dec n) tail)]
                 (cons head x))
               (combinations n tail))))))

user> (require '[clojure.contrib.combinatorics :as combine])
nil
user> (time (last (user/combinations 4 (range 100))))
"Elapsed time: 4379.959957 msecs"
(96 97 98 99)
user> (time (last (combine/combinations (range 100) 4)))
"Elapsed time: 10913.170605 msecs"
(96 97 98 99)

Я настоятельно предпочитаю порядок аргументов [n coll], а не [coll n] - clojure нравится «важный» аргумент дляИ наконец, особенно для функций, имеющих дело с seqs: в основном это для простоты комбинации с (->>) в таких сценариях, как (->> (my-list) (filter even?) (take 10) (combinations 8)).

3 голосов
/ 23 июня 2011

Вы хотите комбинации. Есть функция, чтобы дать вам ленивую последовательность комбинаций прямо здесь в clojure-contrib.

user> (combinations [:a :b :c :d :e] 2)
((:a :b) (:a :c) (:a :d) (:a :e) (:b :c) (:b :d) (:b :e) (:c :d) (:c :e) (:d :e))

(К сожалению, монолитное хранилище clojure-contrib, содержащее этот файл, не рекомендуется в пользу разделения contrib на более мелкие отдельные репозитории, и clojure.contrib.combinatorics, похоже, еще не осуществил переход, поэтому в настоящее время нет простого способа установите эту библиотеку, но вы можете получить код из github, если ничего больше.)

1 голос
/ 23 июня 2011

Зачем использовать захват диапазона и индекса в цикле for?

(let [myseq (list :a :b :c :d)]
    (for [a myseq b myseq] (list a b)))

работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...