Таинственная функция Clojure - PullRequest
0 голосов
/ 08 мая 2020

Я хотел бы написать функцию clojure со следующим поведением:

  (take 4 (floyd))
  => '((1) (2 3) (4 5 6) (7 8 9 10))

  (take 3 (floyd))
  => '((1) (2 3) (4 5 6))

  (take 1 (floyd))
  => '((1)))

Я пробовал использовать partition и partition-all для проверки этих тестов, но мне не удалось найти правильного решения. Если у вас есть идеи, как это сделать, я был бы очень признателен за небольшую помощь. Я начал использовать clojure через несколько недель go, и все еще есть некоторые проблемы.
Спасибо

Ответы [ 3 ]

1 голос
/ 08 мая 2020

невозможно решить с помощью partition / partition-all, так как они разбивают вашу последовательность на части предопределенного размера.

Что вы можете сделать, так это использовать для этого рекурсивную ленивую функцию:

user> (defn floyd []
        (letfn [(f [n rng]
                  (cons (take n rng)
                        (lazy-seq (f (inc n) (drop n rng)))))]
          (f 1 (iterate inc 1))))
#'user/floyd

user> (take 1 (floyd))
;;=> ((1))

user> (take 2 (floyd))
;;=> ((1) (2 3))

user> (take 3 (floyd))
;;=> ((1) (2 3) (4 5 6))

user> (take 4 (floyd))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10))

другой вариант может использовать аналогичный подход, но только отслеживать chunk-start / chunk-size:

user> (defn floyd []
        (letfn [(f [n start]
                  (cons (range start (+ start n))
                        (lazy-seq (f (inc n) (+ start n)))))]
          (f 1 1)))

другой подход - использовать рабочие функции коллекции clojure:

user> (defn floyd-2 []        
        (->> [1 1]
             (iterate (fn [[start n]]
                        [(+ n start) (inc n)]))
             (map (fn [[start n]] (range start (+ start n))))))
#'user/floyd-2

user> (take 4 (floyd-2))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10))

user> (take 5 (floyd-2))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10) (11 12 13 14 15))

user> (take 1 (floyd-2))
;;=> ((1))
1 голос
/ 09 мая 2020

Вот еще один вариант:

(defn floyd []
  (map (fn [lo n] (range lo (+ lo n 1))) 
       (reductions + 1 (iterate inc 1)) 
       (range)))

(take 5 (floyd))
;=> ((1) (2 3) (4 5 6) (7 8 9 10) (11 12 13 14 15))

Это было получено на основании наблюдения, что вам нужна серия возрастающих диапазонов (аргумент (range) для map используется для создания последовательности возрастающих более длинные диапазоны), каждый из которых начинается почти с трех angular числовой последовательности:

(take 5 (reductions + 0 (iterate inc 1)))
;=> (0 1 3 6 10)

Если вместо этого мы начнем эту последовательность с 1, мы получим начальные числа в желаемой последовательности:

(take 5 (reductions + 1 (iterate inc 1)))
;=> (1 2 4 7 11)

Если + 1 внутри сопоставленной функции вас беспокоит, вы можете сделать это вместо:

(defn floyd []
  (map (fn [lo n] (range lo (+ lo n)))
       (reductions + 1 (iterate inc 1))
       (iterate inc 1)))
1 голос
/ 08 мая 2020

Как насчет этого:

(defn floyd []
  (map (fn[n]
         (let [start (/ (* n (inc n)) 2)]
           (range (inc start) (+ start n 2))))
       (iterate inc 0)))

(take 4 (floyd))
...