我正在使用Emacs Lisp,但加载了cl
个包,用于一些常见的lisp功能。
我有一个包含多达50K条目的哈希表,整数键映射到三元组,类似这样(但在实际的lisp中):
{
8 => '(9 300 12)
27 => '(5 125 9)
100 => '(10 242 14)
}
三元组中的第二个值是在构建散列表的复杂算法中计算的分数。我需要收集一个常规的lisp列表,其中包含散列中的所有键,按得分排序(即由值的cadr排序的所有键)。
所以对于上述内容,我需要这个列表:
'(27 100 8)
我目前正在做两个阶段,感觉效率低于预期。
有没有好办法呢?
我当前的解决方案使用maphash
将密钥和值收集到两个新列表中,然后以正常方式执行sort
,引用谓词中的分数列表。但是,感觉我可以将收集和排序结合在一起。
编辑|我也不依赖于使用hash-table,尽管我确实需要对整数键进行恒定的访问时间,这些整数键不是线性间隔的。
编辑2 |看起来实现二叉树排序可能会起作用,树中的标签是分数,值是键...这样我就可以在哈希映射时进行排序。
...继续阅读关于排序算法的维基百科页面
答案 0 :(得分:7)
基本上,您的解决方案是正确的:您需要将密钥收集到列表中:
(defun hash-table-keys (hash-table)
(let ((keys ()))
(maphash (lambda (k v) (push k keys)) hash-table)
keys))
然后对列表进行排序:
(sort (hash-table-keys hash-table)
(lambda (k1 k2)
(< (second (gethash k1 hash-table))
(second (gethash k2 hash-table)))))
可以将密钥集合与排序相结合:您需要将密钥收集到树中,然后“展平”树。但是,只有在处理真正庞大的表时,这才有意义。此外,由于Emacs Lisp编译为字节码,您可能会发现使用内置sort
仍然比使用树更快。还要考虑开发成本 - 您需要编写其价值主要是教育性的代码。
深入研究,收集密钥会分配密钥列表(结果肯定需要它),sort
“就地”操作,所以“简单方法”就像它一样好得到。
“树”方式将分配树(与所需的键列表相同的内存占用量),填充和展平它将是与“collect + sort”方式相同的O(n*log(n))
进程。但是,保持树的平衡,然后“就地”扁平化(即,不分配新的列表)并不是一个简单的练习。
底线是:KISS。