我需要从数百万个哈希映射的懒惰序列中获取20个结果,但是20个基于对哈希映射中的各种值进行排序。
例如:
(def population [{:id 85187153851 :name "anna" :created #inst "2012-10-23T20:36:25.626-00:00" :rank 77336}
{:id 12595145186 :name "bob" :created #inst "2011-02-03T20:36:25.626-00:00" :rank 983666}
{:id 98751563911 :name "cartmen" :created #inst "2007-01-13T20:36:25.626-00:00" :rank 112311}
...
{:id 91514417715 :name "zaphod" :created #inst "2015-02-03T20:36:25.626-00:00" :rank 9866}]
在正常情况下,简单的sort-by
可以完成工作:
(sort-by :id population)
(sort-by :name population)
(sort-by :created population)
(sort-by :rank population)
但是我需要尽可能快地在数百万条记录中执行此操作,并且想要懒惰而不是必须实现整个数据集。
我环顾四周,发现了许多算法的实现,这些算法非常适合于排序一系列值(主要是数字),但是对于我需要的方式来说,哈希映射的延迟序列都没有。
速度&效率是最重要的,我发现的最好的一直是Joy Of Clojure书(第6.4章)中的快速举例,该书确实足以返回所需的结果。
(ns joy.q)
(defn sort-parts
"Lazy, tail-recursive, incremental quicksort. Works against
and creates partitions based on the pivot, defined as 'work'."
[work]
(lazy-seq
(loop [[part & parts] work]
(if-let [[pivot & xs] (seq part)]
(let [smaller? #(< % pivot)]
(recur (list*
(filter smaller? xs)
pivot
(remove smaller? xs)
parts)))
(when-let [[x & parts] parts]
(cons x (sort-parts parts)))))))
(defn qsort [xs]
(sort-parts (list xs)))
工作得很好......
(time (take 10 (qsort (shuffle (range 10000000)))))
"Elapsed time: 551.714003 msecs"
(0 1 2 3 4 5 6 7 8 9)
大!但...
无论我尝试多少,我似乎无法解决如何将其应用于一系列哈希图。
我需要类似的东西:
(take 20 (qsort-by :created population))
答案 0 :(得分:4)
如果你只需要前N个元素,那么完全排序太昂贵了(甚至像JoC中那样懒惰排序:它需要保留几乎所有数据集在内存中)。
您只需扫描(=> (defn top-by [n k coll]
(reduce
(fn [top x]
(let [top (conj top x)]
(if (> (count top) n)
(disj top (first top))
top)))
(sorted-set-by #(< (k %1) (k %2))) coll))
#'user/top-by
=> (top-by 3 first [[1 2] [10 2] [9 3] [4 2] [5 6]])
#{[5 6] [9 3] [10 2]}
)数据集并保留目前为止最好的N项。
SELECT a.*,
lag(amount,1) over (PARTITION BY bond_number ORDER BY
payment_id,jn_date_time)recent_amount,
amount + nvl(lag(amount,1) over (PARTITION BY bond_number ORDER BY
payment_id,jn_date_time),0) running_total
FROM JOURNAL a
ORDER BY payment_id,jn_date_time