为什么 clojure 的 group-by 并不总是保持顺序?
为什么 (group-by Identity (range 1 50)) 返回类似
{32 [32], 1 [1], 33 [33], 2 [2], 34 [34], 3 [3], 35 [35 ]...
与多线程相关吗?有什么办法解决吗?
……这会违反合同吗?
返回 coll 元素的映射,该映射由每个元素上的 f 结果作为键。每个键的值将是相应元素的向量,按照它们在 coll 中出现的顺序。
Why does (group-by identity (range 1 50)) return results like
{32 [32], 1 [1], 33 [33], 2 [2], 34 [34], 3 [3], 35 [35]...
Is it multi-threading related? Is there any way around it?
...and does it break it's contract?
Returns a map of the elements of coll keyed by the result of f on each element. The value at each key will be a vector of the corresponding elements, in the order they appeared in coll.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
尝试在 REPL 中输入
(type (group-byidentity (range 1 50)))
。您可以看到结果实际上是一个哈希映射(属于clojure.lang.PersistentHashMap
类)。这意味着它是无序的:原则上,REPL 可以按键/值对的任何顺序输出打印的映射文字。它以这种方式打印的实际原因与 Clojure 的哈希映射实现有关——就数据结构而言,它实际上是一棵宽树,其中每个节点最多可以有 32 个子节点(因此输出中的初始 32 ; 回想一下,Clojure 向量和映射通常被认为具有 O(log32N)) 的查找成本。 这篇博客文章有一个很好的总结。
不,它并没有违反
group-by
的约定。合约仅指定映射值元素的顺序,而不是映射本身的顺序。Try entering
(type (group-by identity (range 1 50)))
in your REPL. You can see that the result is actually a hash map (of classclojure.lang.PersistentHashMap
). This means that it's unordered: in principle the REPL could output the printed map literal in any order of key/value pairs.The actual reason why it's printed the way it's printed has to do with Clojure's implementation of a hash map -- in terms of data structures, it's actually a wide tree where each node can have up to 32 children (hence the initial 32 in your output; recall that Clojure vectors and maps are often cited to have lookup cost of O(log32N)). This blog article has a good summary.
And no, it doesn't violate the contract of
group-by
. The contract only specifies the ordering of the map's values' elements, not the ordering of the map per se.