2014-12-16 2 views
4

Пытается написать рекурсивную функцию, которая добавляет последовательные пары в вектор.Clojure-Как добавить последовательные пары в вектор?

[1 2 3 4] => [3 5 7] 

Довольно много застрял & это то, что я в настоящее время:

(def tmp [ 1 2 3 4]) 

user> (map #(+ (second %) (first %)) (partition-all 2 tmp)) 

Это неправильно, поскольку это добавляет только пары & не последовательных пар. Я получаю [3 7] вместо [3 5 7]

+0

В моем опыте, вы могли бы сделать лучше, чтобы написать свой собственный (неизменно рекурсивной, если мы включаем 'повторялись 's) версий стандартных функций библиотеки, чем писать ab-initio-решения для задач, которые стандартные функции решают в одной строке. Вам предлагаются два таких решения. – Thumbnail

ответ

7

Раздел содержит дополнительный аргумент, указывающий, как далеко продвинуться вперед между каждым разделом.

(map #(apply + %) (partition 2 1 [1 2 3 4 5])) =>

(3 5 7 9)

+0

как бы я это сделал, если бы захотел использовать рекурсию? – AaronGarcia

8

Вот еще один из возможных решений:

(def tmp [1 2 3 4]) 

(map + tmp (rest tmp)) 
1

Вы просите рекурсивной функции, и даже если в большинстве случаев установить и список функций предпочтительнее выше создавая собственную рекурсивную функцию, это не всегда возможно. Эта проблема также очень легко записывается рекурсивно по идиоматическому функциональному способу с использованием аккумулятора

Идея заключается в том, что вы начинаете с пустого аккумулятора и строите свой результат шаг за шагом. Аккумулятор (acc в этом фрагменте кода) проведет ответ в конце.

(defn add-pairs [v1] 
    (loop [the-list v1 acc []] 
    (if (next the-list) ;; checks wether there's more than 1 left in the-list 
     (recur (rest the-list) 
      (conj acc (+ (first the-list) (second the-list)))) 
    acc))) 

Что здесь происходит? Вы передаете вектор [1 2 3 4] в v1. Затем цикл начинается и в нем две переменные инициализируются:

the-list <- [1 2 3 4] 
acc [] 

достаточно просто сумма двух первых элементов (+ (first the-list) (second the-list) добавляются к аккумулятору. Затем с recur цикл вызывается снова, передавая остальную часть списка (rest the-list) и аккумулятор, теперь содержащий 3 (являющийся суммой двух первых элементов). Новые vaues являются:

the-list <- [2 3 4] 
acc [3] 

следующие шаги:

the-list <- [3 4] 
acc [3 5] 

the-list <- [4] 
acc [3 5 7] 

Тогда, если условие больше не выполняется и условие еще возвращается (обычно является аккумулятор, теперь держа раствор).

Общая идея

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

Также очень классика в этой конкретной проблеме состоит в том, что входной набор теряет свой первый элемент на каждом шаге. (отдых) Здесь очень практично (cdr в большинстве других lisps).

общий вид

Петля форма/повторятся в Clojure очень хорошо, но во многих других языках, этот синтаксис отсутствует. Очень классическое решение состоит в том, чтобы иметь две функции: одну рекурсивную, которая выполняет цикл, и одно с тем же именем, но другую arity, которая выполняет инициализацию аккумулятора. Simpler в коде, чем это объяснить, так вот она в какой-то составил Java-подобный синтаксис:

function add-pairs(v1 acc) { 
    if (cond) 
     //do stuff to v1 and acc 
     add-pairs(v1 acc) 
    else 
     return acc } 

function add-pairs(v1) { 
    return add-pairs(v1,[]) 
} 

var result = add-pairs([42 666 1447]) 
+0

Большое спасибо за пошаговое объяснение. Будет играть вокруг wi/this more. – AaronGarcia

+0

Очень красивое введение в рекурсию В Clojure. Кстати, использование 'count' для проверки того, что что-то пустое, - плохая идея. Он линейный по размеру ленивой коллекции - даже тот, который был подсчитан ранее (счетчик не кэшируется). Просто проверьте '(empty? (Next the-list))', намного дешевле. – noisesmith

+0

@noismith, правда, я сомневался в его использовании, но я не сделал этого, потому что это кажется только еще одним шагом для объяснения (поскольку нильское закрепление и правдивость вступают в игру с более идиоматическим способом проверки). Тем не менее, это плохая идея, не использующая правильный путь в примере. поэтому я его изменю. – Peter

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