我需要计算特定整数对在某些过程中出现的次数(使用局部敏感散列法检测相似图像的启发式方法 - 整数表示图像,下面的“邻居”是具有相同散列值的图像,因此计数表示有多少不同的哈希连接给定的图像对)。
计数存储为从(有序)对到计数(matches
如下)的映射。
输入(nbrs-list
下面)是被认为是邻居的整数列表的列表,其中内部列表(“邻居”)中的每个不同(有序)对都应该被计算在内。因此,例如,如果nbrs-list
是,[[1,2,3],[10,8,9]]
那么对是[1,2],[1,3],[2,3],[8,9],[8,10],[9,10]
。
该例程collect
被多次调用;该matches
参数会累积结果,并且nbrs-list
每次调用都是新的。最小的邻居数(内部列表的大小)为 1,最大的约为 1000。in 中的每个整数在nbrs-list
任何调用中只出现一次collect
(这意味着,在每次调用中,没有任何对出现超过一次)并且整数覆盖范围 0 - 1,000,000(因此 的大小nbrs-list
小于 1,000,000 - 因为每个值只出现有时它们会成组出现 - 但通常大于 100,000 - 因为大多数图像没有邻居)。
我已经从一大块代码中提取了这些例程,所以它们可能包含小的编辑错误,抱歉。
(defn- flatten-1
[list]
(apply concat list))
(defn- pairs
([nbrs]
(let [nbrs (seq nbrs)]
(if nbrs (pairs (rest nbrs) (first nbrs) (rest nbrs)))))
([nbrs a bs]
(lazy-seq
(let [bs (seq bs)]
(if bs
(let [b (first bs)]
(cons (if (> a b) [[b a] 1] [[a b] 1]) (pairs nbrs a (rest bs))))
(pairs nbrs))))))
(defn- pairs-map
[nbrs]
(println (count nbrs))
(let [pairs-list (flatten-1 (pairs nbrs))]
(apply hash-map pairs-list)))
(defn- collect
[matches nbrs-list]
(let [to-add (map pairs-map nbrs-list)]
(merge-with + matches (apply (partial merge-with +) to-add))))
所以上面的代码将每组邻居扩展为有序对;创建从对到的映射1
;然后使用添加值组合地图。
我希望它运行得更快。我不知道如何避免对的 O(n^2) 扩展,但我想我至少可以通过避免这么多中间结构来减少恒定开销。同时,我希望代码相当紧凑和可读......
哦,现在我超过了“GC 开销限制”。所以减少内存使用/流失也是一个优先事项:o)
[也许这太具体了?我希望这些课程是一般性的,并且似乎没有很多关于优化“真实”clojure 代码的帖子。此外,我可以分析等,但我的代码看起来很丑,我希望有一个明显的、更干净的方法——特别是对于对扩展。]