Ruby sort_by保持未排序的原始顺序



我有一个散列,看起来像:

{ "3g3dsd3" => {"price"=>0.12, "avg"=>81, "top"=>true}, "1sf3af" => {"price"=>0.14, "avg"=>121, "top"=>false}...}

我想重新排序,这样"top"=>true的项目会在顶部,但除此之外,这些项目会保持以前的顺序,这意味着top值相同的项目不会在时间之间改变顺序。

我在原始文档中找不到sort_by保持未排序属性顺序的证据。

我该怎么做?

您可以通过合并with_index来使sort_by稳定。

代替:

collection.sort_by { |...| ... }

你写:

collection.sort_by.with_index { |(...), i| [..., i] }

应用于您的问题:

hash.sort_by { |_k, v| v['top'] ? 0 : 1 }                      # unstable
hash.sort_by.with_index { |(_k, v), i| [v['top'] ? 0 : 1, i] } # stable

sort_by特别指出:

不能保证结果是稳定的。当两个键相等时,相应元素的顺序是不可预测的。

这意味着你的问题是有根据的。

在这种情况下,您可以使用partition将集合一分为二。然后按照你想要的方式把它们粘在一起。

top, non_top = hash.partition { |key, hash| hash['top'] }
result = (top + non_top).to_h

partition保持原始数组的顺序。


如果您是一个one-line的粉丝,在这种情况下,下面的操作也是一样的。

result = hash.partition { |key, hash| hash['top'] }.flatten(1).to_h

Rubysort / sort_by不稳定。然而,您可以使用原始输入中的索引作为决胜局:Ruby中的排序稳定吗?

这里有一种方法可以重新排序哈希的键值对,而无需将哈希转换为一个或多个数组,然后在修改后将这些数组转换回哈希。

假设

h = { "2rh4abc" => {"price"=>0.18, "avg"=>130, "top"=>false },
"3g3dsd3" => {"price"=>0.12, "avg"=>81,  "top"=>true  },
"1sf3af"  => {"price"=>0.14, "avg"=>121, "top"=>false } }

然后

top_key = h.find { |_,v| v["top"] == true }.first
#=> "3g3dsd3"
{ top_key=>h[top_key] }.merge(h.reject { |k,_| k == top_key })
#=> {"3g3dsd3"=>{"price"=>0.12, "avg"=>81, "top"=>true},
#    "2rh4abc"=>{"price"=>0.18, "avg"=>130, "top"=>false},
#    "1sf3af"=>{"price"=>0.14, "avg"=>121, "top"=>false}}

如果h可以突变(就地修饰(,则可以简化为:

{ top_key=>h.delete(top_key) }.merge(h)
#=> {"3g3dsd3"=>{"price"=>0.12, "avg"=>81, "top"=>true},
#    "2rh4abc"=>{"price"=>0.18, "avg"=>130, "top"=>false},    
#    "1sf3af"=>{"price"=>0.14, "avg"=>121, "top"=>false}} 

最新更新