我有一个散列,看起来像:
{ "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}}