我正在研究this problem
我的解决方案是:
(fn [s]
(map #(first %) (group-by identity s)))
前三次测试通过,最后一次测试失败。
由于
(group-by identity (range 50)
给出无序的结果。但我的解决方案强烈依赖于分组功能的有序功能。也就是说,必须保持结果映射中每个键的顺序。即使the Doc不能保证这一点,这几乎也是如此。
真奇怪的是:
你看,当参数超过32时,分组功能会给出错误的顺序。结果不是随机的,而是溢出的元素在第一个元素之后。
为什么?
如何保留分组功能的有序功能还是有更好的解决方案?
答案 0 :(得分:6)
通用地图的任何排序都是实施细节。
使用哈希表实现较大的映射,这通常不会保留顺序。对于小地图,散列的开销高于线性查找的开销。因此,优化是针对小地图以数组地图开始生命,这确实保留了顺序。随着添加更多元素,地图将转换为哈希映射。
(class (group-by identity (range 8)))
;=> clojure.lang.PersistentArrayMap
(class (group-by identity (range 32)))
;=> clojure.lang.PersistentHashMap
这种转换发生在32个元素之前,但是没有挖掘内部结构,我怀疑初始哈希表有32个插槽,因此在哈希冲突策略启动之前不会发生混乱。
就4Clojure implement distinct
问题而言,您可以使用原始集合中sort-by
上的.indexOf
来挽救您的解决方案。
扰流:
(fn [s] (排序方式#(。indexOf s%) (map#(first%)(group-by identity s))))
答案 1 :(得分:0)
听起来你想要sorted-map
:
=> (apply sorted-map (flatten (seq (group-by identity (range 50)))))
{0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7, 8 8, 9 9, 10 10, 11 11, 12 12, 13 13, 14 14, 15 15, 16 16, 17 17, 18 18, 19 19, 20 20, 21 21, 22 22, 23 23, 24 24, 25 25, 26 26, 27 27, 28 28, 29 29, 30 30, 31 31, 32 32, 33 33, 34 34, 35 35, 36 36, 37 37, 38 38, 39 39, 40 40, 41 41, 42 42, 43 43, 44 44, 45 45, 46 46, 47 47, 48 48, 49 49}
如您所见,当您处理小地图时,clojure可能会选择已排序的实现。但是,这是一个实现细节,不能保证。 sorted-map
返回一个映射,其中键的迭代顺序保证被排序。
答案 2 :(得分:0)
将值添加到地图中时,将返回相应类型的集合。在PersistentArrayMaps的情况下,当大小超过16个项目时(参见source第177行),它返回一个PersistentHashMap,而不是维持顺序。
虽然我无法找到切换第33个元素的行为的直接原因,但我知道处理Vector的方式是32个块,因此更新一个元素不需要全新的向量 - 只需要更换块。它可能与此有关,或者与其他一些优化行为有关。