Вещи, которые выглядят для меня потенциально медлительными (хотя для уверенности вам придётся сравниться с эталоном ....)
- Все ваши номера указаны в штучной упаковке.Это сделает все, что вы делаете, намного медленнее, чем использование примитивов.Это не очень идиоматично, но вы можете использовать примитивные массивы в Clojure, если хотите получить это ускорение.
- Сокращение по сравнению с субвеком в настоящее время создает много временных объектов.В работе есть патч, чтобы исправить это (http://dev.clojure.org/jira/browse/CLJ-894), но вам, возможно, придется подождать Clojure 1.4 или 1.5 для этого.
- Это помогает сделать
(set! *unchecked-math* true)
, чтобы улучшить производительность целочисленных операций (очевидно,вам нужно быть немного более осторожным, если возможны переполнения)
Если бы я хотел, чтобы это работало очень быстро в Clojure, я бы, вероятно, прибегнул к примитивным массивам и циклически с примитивными индексами:
(set! *unchecked-math* true)
(defn count-inversions [coll]
(let [^ints integers (int-array coll)
size (long (count integers))]
(loop [c (long 0)
i (long 0)]
(if (>= i size)
c
(recur
(loop [c (long c)
v (aget integers i)
j (inc i)]
(if (>= j size)
c
(recur (long (if (> v (aget integers j)) (inc c) c)) v (inc j))))
(inc i))))))
(time (count-inversions (for [i (range 100000)] (rand-int 100))))
"Elapsed time: 16036.651863 msecs"
т.е. этот код подсчитывает все инверсии в 100 000 целых чисел примерно за 16 секунд на моем компьютере (с Clojure 1.3)