[英]Ruby - Sort a hash by order of an array
我有一个array
和一个hash
,我想要实现的是根据数组中的排序对hash
(每个哈希中的每个id
)进行排序,如果id
(在hash
中)不存在于my_array
中,它们不应该被删除,而只是在排序中被压低。
my_array = [4, 2, 5, 3, 1]
hash = [
{"id" => 1, "field_name" => "foo"},
{"id" => 2, "field_name" => "bar"},
{"id" => 3, "field_name" => "abc"},
{"id" => 4, "field_name" => "zsh"},
{"id" => 5, "field_name" => "kql"},
{"id" => 6, "field_name" => "plo"},
{"id" => 7, "field_name" => "cde"}
]
需要 output
[
{"id" => 4, "field_name" => "zsh"},
{"id" => 2, "field_name" => "bar"},
{"id" => 5, "field_name" => "kql"},
{"id" => 3, "field_name" => "abc"},
{"id" => 1, "field_name" => "foo"},
{"id" => 6, "field_name" => "plo"},
{"id" => 7, "field_name" => "cde"}
]
感谢任何帮助,并提前致谢!
虽然可能有更优雅的方法来做到这一点,但我认为下面的解决方案非常清楚。 它使用您的id元素数组作为 Enumerable object 到 map,返回匹配的 Hash object 以及迭代期间遇到的每个"id"
键的匹配值(如果找到),然后删除未找到匹配项的任何元素,例如#map 返回的数组返回nil
。
使用 Ruby 3.1.2:
id_order = [4, 2, 5, 3, 1]
array_of_hashes = [
{"id" => 1, "field_name" => "foo"},
{"id" => 2, "field_name" => "bar"},
{"id" => 3, "field_name" => "abc"},
{"id" => 4, "field_name" => "zsh"},
{"id" => 5, "field_name" => "kql"},
{"id" => 6, "field_name" => "plo"},
{"id" => 7, "field_name" => "cde"}
]
id_order.map { |id| array_of_hashes.detect { |h| h["id"] == id } }.compact
这会正确返回第一个数组中指定的排序结果:
#=>
[{"id"=>4, "field_name"=>"zsh"},
{"id"=>2, "field_name"=>"bar"},
{"id"=>5, "field_name"=>"kql"},
{"id"=>3, "field_name"=>"abc"},
{"id"=>1, "field_name"=>"foo"}]
请注意,它不会为 ID 6
或7
返回 Hash 个对象,因为它们不存在于要搜索的 ID 数组中。 您可以调整 #map 以将它们视为传递(尽管您没有解释它们应该如何或为什么出现在结果数组的末尾)或将它们添加到要搜索的元素数组中,这将是首选方法。 但是,由于它们没有在您的原始帖子中解决,如果没有找到匹配的 ID,这实际上是正确的 output。
my_array = [4, 7, 5, 3, 1]
arr = [
{"id" => 1, "field_name" => "foo"},
{"id" => 2, "field_name" => "bar"},
{"id" => 3, "field_name" => "abc"},
{"id" => 4, "field_name" => "zsh"},
{"id" => 5, "field_name" => "kql"},
{"id" => 6, "field_name" => "plo"},
{"id" => 7, "field_name" => "cde"}
]
请注意,我已经更改了问题中给出的my_array
并将数组重命名为更合适的名称。
arr.sort_by.with_index do |h,i|
my_array.include?(h["id"]) ? [0, h["id"]] : [1,i]
end
#=> [{"id"=>1, "field_name"=>"foo"},
# {"id"=>3, "field_name"=>"abc"},
# {"id"=>4, "field_name"=>"zsh"},
# {"id"=>5, "field_name"=>"kql"},
# {"id"=>7, "field_name"=>"cde"},
# {"id"=>2, "field_name"=>"bar"},
# {"id"=>6, "field_name"=>"plo"}]
请参阅Enumerable#sort_by 。 该方法使用Array#<=>对元素进行排序。 请特别参阅文档中的第三段<=>
。
下面我列出了sort_by
为arr
的每个元素使用的 arrays。
{"id" => 1, "field_name" => "foo"} -> [0, 1]
{"id" => 2, "field_name" => "bar"} -> [1, 1]
{"id" => 3, "field_name" => "abc"} -> [0, 3]
{"id" => 4, "field_name" => "zsh"} -> [0, 4]
{"id" => 5, "field_name" => "kql"} -> [0, 5]
{"id" => 6, "field_name" => "plo"} -> [1, 5]
{"id" => 7, "field_name" => "cde"} -> [0, 7]
如果[type, x]
是sort_by
用于排序的数组,它将把type 0
的所有元素放在type = 1
的元素之前。 为了打破平局,它按x
对元素进行排序。 对于type = 1
, x
是元素的索引,它使它们在最后保持有序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.