我有一个需要按imp
排序的哈希数组,我希望从中获取特定属性。
array_of_hash is
[
{
:id => "9",
:subsystem => "xyz",
:component => "xyz",
:imp => "1",
:old_serial => "55q",
:current_serial => nil,
:old_num => "same",
:current_num => nil,
:acceptable_nums => [
"asdf",
"qwer",
"zxcv",
"poiu"
]
},
{
:id => "10",
:subsystem => "xyz",
:component => "xyz",
:imp => "4",
:old_serial => "56t",
:current_serial => nil,
:old_num => "same",
:current_num => nil,
:acceptable_nums => [
"asdf",
"qwer",
"zxcv",
"poiu"
]
},
{
:id => "11",
:subsystem => "xyz",
:component => "xyz",
:imp => "3",
:old_serial => "57s",
:current_serial => nil,
:old_num => "same",
:current_num => nil,
:acceptable_nums => [
"asdf",
"qwer",
"zxcv",
"poiu"
]
},
{
:id => "14",
:subsystem => "xyz",
:component => "xyz",
:imp => "2",
:old_serial => "58r",
:current_serial => nil,
:old_num => "same",
:current_num => nil,
:acceptable_nums => [
"asdf",
"qwer",
"zxcv",
"poiu"
]
}
]
第一步,排序
array_of_hash.sort_by {|hash| hash[:imp].to_i}
然后我想要特定的属性
期望输出有一些条件
{
:imp => "1-4", #It should be range
:old_serial => "55q,56r,57s,58t", #old_serial number should be separated with comma respectively
:old_num => "same",
:acceptable_nums => [
"asdf",
"qwer",
"zxcv",
"poiu"
]
}
我无法弄清楚如何做到这一点。
答案 0 :(得分:1)
您需要sort_by
,group_by
和map
的组合:
p array_of_hash.sort_by { |h| h[:imp] }
.group_by{ |h| h.values_at(:acceptable_nums, :old_num) }
.map{ |(old_num, nums), hashes|
{
imp: hashes.map{ |h| h[:imp].to_i },
old_serial: hashes.map{ |h| h[:old_serial] }.join(','),
old_num: old_num,
acceptable_nums: nums
}
}
# [{:imp=>[1, 2, 3, 4], :old_serial=>"55q,58r,57s,56t", :old_num=>["asdf", "qwer", "zxcv", "poiu"], :acceptable_nums=>"same"}]
输出是一个哈希数组。每个唯一的old_num
和acceptable_nums
对都会有一个哈希值。在您的示例中,所有哈希都具有相同的对,因此只输出一个哈希值。
对于从[1,2,3,4]
到"1-4"
的所需转换,slice_when
的文档就是这样做的:
a = [1,2,4,9,10,11,12,15,16,19,20,21]
b = a.slice_when {|i, j| i+1 != j }
p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
p c #=> [[1, 2], [4], "9-12", [15, 16], "19-21"]
d = c.join(",")
p d #=> "1,2,4,9-12,15,16,19-21"
答案 1 :(得分:1)
imps, old_serials = array_of_hash.map { |h| [h[:imp], h[:old_serial]] }.
sort_by(&:first).
transpose
#=> [["1", "2", "3", "4"], ["55q", "58r", "57s", "56t"]]
{ imp: "%d-%d" % imps.map(&:to_i).minmax, old_serial: old_serials.join(',') }.
merge(array_of_hash.first.select { |k,_| [:old_num, :acceptable_nums].include?(k) })
#=> {:imp=>"1-4", :old_serial=>"55q,58r,57s,56t", :old_num=>"same",
# :acceptable_nums=>["asdf", "qwer", "zxcv", "poiu"]}
请注意
array_of_hash.first.select { |k,_| [:old_num, :acceptable_nums].include?(k) }
# => {:old_num=>"same", :acceptable_nums=>["asdf", "qwer", "zxcv", "poiu"]}
答案 2 :(得分:0)
如果你逐步分解它,它会更容易阅读。
old_serial_numbers = array_of_hash.collect {|h| h[:old_serial]}.join(',')
reject_hash_keys = [:old_serial, :id, :subsystem, :component, :current_num, :current_serial]
clean_hash = array_of_hash.map do |hash|
hash.reject! {|k| reject_hash_keys.include? k }
hash.merge(old_serial: old_serial_numbers)
end
clean_hash.sort_by {|hash| hash[:imp].to_i}