2012-06-19 2 views
2

Посмотрите на приведенную ниже функцию. Я хочу передать вектор факторов и проверить, является ли какой-либо из элементов в векторе фактором x. Как мне это сделать?функция для нахождения, если x кратно y

(defn multiple? 
    "Takes a seq of factors, and returns true if x is multiple of any factor." 
    ([x & factors] (for [e m])) 
    ([x factor] (= 0 (rem x factor)))) 

ответ

1

Вы можете попробовать использовать some и map:

(defn multiple? [x & factors] 
    (some zero? (map #(rem x %) factors))) 

Также some возвращает nil, если все тесты терпят неудачу, если вам это нужно на самом деле вернуть false, вы могли бы поставить true? там:

(defn multiple? [x & factors] 
    (true? (some zero? (map #(rem x %) factors)))) 

Обратите внимание, что some замыкание на замыкание и map лениво, поэтому multiple? останавливается, как только будет найден матч. например следующие тесты кода в отношении последовательности 1,2,3,4,....

=> (apply multiple? 10 (map inc (range))) 
true 

Очевидно, что это вычисление может быть прекращено только если multiple? не испытывает от каждого числа в последовательности.

0

Попробуйте это, используя явную хвостовую рекурсию:

(defn multiple? [x factors] 
    "if any of the elements in the vector is a factor of x" 
    (loop [factors factors] 
     (cond (empty? factors) false 
       (zero? (rem x (first factors))) true 
       :else (recur (rest factors))))) 

преимущества вышеуказанного раствора включает в себя: он остановится, как только он обнаруживает, если какое-либо из элементов в векторе является фактором x, без итерация по всему вектору; он эффективен и работает в постоянном пространстве благодаря использованию хвостовой рекурсии; и он возвращает непосредственно логический результат, нет необходимости рассматривать случай возврата nil. Используйте его так:

(multiple? 10 [3 4]) 
=> false 

(multiple? 10 [3 4 5 6]) 
=> true 

Если вы хотите, чтобы избежать необходимости явно передавать вектор (для вызова процедуры, как это: (multiple? 10 3 4 5 6))), то просто добавьте & к списку параметров, так же, как это было в вопрос.

+0

Параметр 'map' /' some' решение имеет такое же поведение. (Он не проверяет каждое число в последовательности.) – huon

1

Вы можете решить эту проблему, используя только some.

=> (defn multiple? [x factors] 
(some #(zero? (rem x %)) factors)) 
#'user/multiple? 
=> (= true (multiple? 10 [3 4])) 
false 
=> (= true (multiple? 10 [3 4 5 6])) 
true 

some остановит свой первый фактор.

+1

Ах, нечестно отправить ответ, который идентичен другому ответу, тем более, что ваш ответ более чем на 20 минут позже первоначального ответа. – huon

+0

@dbaupp Я не думаю, что мой ответ идентичен вашему. Этот использует только «некоторые». Ваш использует 'some' и' map'. –

+0

Ах, я пропустил это.Мои извинения. :) (Кроме того, 'true?' - более аккуратный способ написать '= true') – huon

0

Clojurian способ написать более универсальную функцию: вместо ответа на истинный/ложный вопрос он будет возвращать все факторы x. И поскольку последовательности ленивы, это почти так же эффективно, если вы хотите узнать, пуст он или нет.

(defn factors [x & fs] 
    (for [f fs :when (zero? (rem x f))] f)) 

(factors 5 2 3 4) 
=>() 

(factors 6 2 3 4) 
=> (2 3) 

, то вы можете ответить на свой вопрос, просто с помощью empty?:

(empty? (factors 5 2 3 4)) 
=> true 

(empty? (factors 6 2 3 4)) 
=> false 
+0

Использование 'filter' более идиоматично, чем' for': '(filter # (zero? (Rem x%)) fs)' – huon

+0

Хороший комментарий, я согласен. Я использовал 'for', потому что @ murtaza52 пытался использовать его в самом вопросе. – dimagog

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