Различные решения для реализации Clojure проблемы

Вот проблемный Оператор:

Определите процедуру, которая берет три числа в качестве аргументов и возвращает сумму квадратов этих двух большего числа.

Решение долго,

(defn large [x y]
(if (> x y) x y))

(defn large-3 [x y z]
(if(> (large x y) z) (large x y) z))

(defn small [x y]
(if (< x y) x y))

(defn small-3 [x y z]
(if (< (small x y) z ) (small x y) z))

(defn second-largest [x y z]
  (let [greatest (large-3 x y z)
    smallest (small-3 x y z)]
    (first (filter #(and (> greatest %) (< smallest %)) [x y z]))))

(defn square [a]
  (* a a)
)

(defn sum-of-square [x y z]
  (+ (square (large-3 x y z)) (square (second-largest x y z))))

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

5
задан Arun R 1 February 2010 в 19:13
поделиться

3 ответа

(См. Последовательную версию проблемы вместе с ленивым решением в моем втором обновлении этого ответа ниже.)

(defn square [n]
  (* n n))

;; generalises easily to larger numbers of arguments
(defn sum-of-larger-squares [x y z]
  (apply + (map square (take 2 (reverse (sort [x y z]))))))

;; shorter; generalises easily if you want
;; 'the sum of the squares of all numbers but n smallest'
(defn sum-of-larger-squares [x y z]
  (apply + (map square (drop 1 (sort [x y z])))))

Обновление:

Чтобы расширить комментарии из вышесказанного, простое обобщение первой версии состоит в том, чтобы это:

(defn sum-of-larger-squares [n & xs]
  (apply + (map square (take n (reverse (sort xs))))))

Вторая версия прямо обобщает версию, которую Артур опубликовал тем временем:

(defn sum-of-larger-squares [n & xs]
  (apply + (map square (drop n (sort xs)))))

Кроме того, я видел точно такую ​​же проблему, решаемую в Scheme, возможно, даже на SO ... Она включала несколько забавных решений, как тот, который вычисляет некоторые из всех трех квадратов, а затем вычитает наименьший квадрат (это очень просто выразить с помощью примитивов схемы). Это «неэффективно» в том смысле, что вычисляет один лишний квадрат, но, безусловно, очень хорошо читается. К сожалению, сейчас не удается найти ссылку.

Обновление 2:

В ответ на комментарий Артура Ульфельдта по вопросу, ленивое решение (надеюсь, интересного) другой версии проблемы . Сначала код, объяснение ниже:

(use 'clojure.contrib.seq-utils) ; recently renamed to clojure.contrib.seq

(defn moving-sum-of-smaller-squares [pred n nums]
  (map first
       (reductions (fn [[current-sum [x :as current-xs]] y]
                     (if (pred y x)
                       (let [z (peek current-xs)]
                         [(+ current-sum (- (* z z)) (* y y))
                          (vec (sort-by identity pred (conj (pop current-xs) y)))])
                       [current-sum
                        current-xs]))
                   (let [initial-xs (vec (sort-by identity pred (take n nums)))
                         initial-sum (reduce + (map #(* % %) initial-xs))]
                     [initial-sum initial-xs])
                   (drop n nums))))

Библиотека clojure.contrib.seq-utils (или c.c.seq ) предназначена для функции сокращений . Вместо этого можно было бы использовать iterate , но не без некоторой дополнительной сложности (если только кто-то не захочет рассчитать длину последовательности чисел, которые будут обрабатываться в начале, что будет противоречить цели сохранения как можно более ленивый).

Объяснение с примером использования:

user> (moving-sum-of-smaller-squares < 2 [9 3 2 1 0 5 3])
(90 13 5 1 1 1)

;; and to prove laziness...
user> (take 2 (moving-sum-of-smaller-squares < 2 (iterate inc 0)))
(1 1)

;; also, 'smaller' means pred-smaller here -- with
;; a different ordering, a different result is obtained
user> (take 10 (moving-sum-of-smaller-squares > 2 (iterate inc 0)))
(1 5 13 25 41 61 85 113 145 181)

Обычно (скользящая сумма-меньших квадратов пред n & nums) генерирует ленивую последовательность сумм квадратов n пред-наименьшие числа во все более длинных начальных фрагментах исходной последовательности чисел, где "пред-наименьшее" означает наименьшее с учетом порядка, индуцированного предикатом пред . При пред = > вычисляется сумма n наибольших квадратов.

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

С другой стороны, он выполняет большую сортировку; Я считаю, что на самом деле не стоит пытаться оптимизировать эту часть, так как сортируемые последовательности всегда имеют длину n элементов, и на каждом этапе существует максимум одна операция сортировки (нет, если сумма не требует корректировки ).

3
ответ дан 18 December 2019 в 09:07
поделиться
(defn foo [& xs]
  (let [big-xs (take 2 (sort-by - xs))]
    (reduce + (map * big-xs big-xs))))
8
ответ дан 18 December 2019 в 09:07
поделиться

; почему только 3? как насчет N

(defn sum-of-squares [& nums]  
  (reduce + (map #(* % %) (drop 1 (sort nums)))))

или, если вы хотите «сумму двух наибольших чисел:

(defn sum-of-squares [& nums]  
  (reduce + (map #(* % %) (take 2 (reverse (sort nums))))))

(возьмите 2 (переверните (отсортируйте числа))) из ответа Михала Марчика.

7
ответ дан 18 December 2019 в 09:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: