Ruby on rails 在ruby中从排列好的散列中切块
我有一个散列,其中键是按排序顺序排列的,散列大小超过1000。如何根据范围将哈希划分为块 示例:-Ruby on rails 在ruby中从排列好的散列中切块,ruby-on-rails,ruby,Ruby On Rails,Ruby,我有一个散列,其中键是按排序顺序排列的,散列大小超过1000。如何根据范围将哈希划分为块 示例:- h_main = {"1" => "a", "2" => "b", "9" => "c", .............. "880" => "xx", "996" => "xyz
h_main = {"1" => "a", "2" => "b", "9" => "c", .............. "880" => "xx", "996" => "xyz", "998" => "lll", "1050" => "mnx"}
我必须根据范围将上述散列划分为分类器散列块:-
h_result = {"1-100" => {"1" => "a", "2" => "b", "9" => "c" ..... "99" => "re"},
"101-200" => {}
....
....
"900-1000" => {"996" => "xyz", "998" => "lll"},
"1000-1100" => {"1050" => "mnx"}
}
我可以通过应用每个循环来完成,然后可以添加条件来合并各个散列中的键值对,但这是一个漫长的过程
请提前提供优化解决方案,谢谢。我会这样做,但不确定您已经做了什么 创建大哈希:
hash = {}
1000.times do |x|
hash[x] = "hi!"
end
按范围切片:
hash.slice(*(1 .. 100))
=> # keys from 1 .. 100
生成所需的哈希:
def split_hash(range, hash)
end_result = {}
(hash.count / range).times do |x|
range_start = (range * x) + 1
range_end = range_start + range
end_result["#{range_start}-#{range_end}"] = hash.slice(*(range_start .. range_end)) # slice returns a hash which was desired. If you can convert to an array you gain range access as slice still iterates but is performative. if you are OK with an array: hash.to_a[range_start .. range_end]
end
end_result
end
见和
步骤如下
group_size = 10
a = h.keys
#=> ["11", "12", "19", "28", "29", "42", "47", "74", "76"]
b = a.slice_when { |k1,k2| k2.to_i/group_size > k1.to_i/group_size }
#=> #<Enumerator: #<Enumerator::Generator:0x000056fa312199b8>:each>
最后,
b.each_with_object({}) do |key_group,g|
start_range = group_size * (key_group.first.to_i/group_size)
g["%d-%d" % [start_range, start_range+group_size-1]] =
h.slice(*key_group)
end
#=> {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"},
# "20-29"=>{"28"=>"xx", "29"=>"xyz"},
# "40-49"=>{"42"=>"lll", "47"=>"mnx"}}
请注意:
e = b.each_with_object({})
#=> #<Enumerator: #<Enumerator:
# #<Enumerator::Generator:0x0000560a0fc12658>:each>:
# each_with_object({})>
e.to_a
#=> [[["11", "12", "19"], {}], [["28", "29"], {}], [["42", "47"], {}]]
然后执行块计算
start_range = group_size * (key_group.first.to_i/group_size)
#=> 10 * (11/10) => 10
g["%d-%d" % [start_range, start_range+group_size-1]] =
h.slice(*key_group)
#=> g["%d-%d" % [10, 10+10-1]] = h.slice("11", "12", "19")
#=> g["10-19"] = {"11"=>"a", "12"=>"b", "19"=>"c"}
#=> {"11"=>"a", "12"=>"b", "19"=>"c"}
现在,
然后,枚举器e
生成另一个元素,将其传递给块,并分配块变量
key_group,g = e.next
#=> [["28", "29"], {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"}}]
key_group
#=> ["28", "29"]
g #=> {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"}}
请注意,g
的值已更新。块计算现在与之前一样进行,之后:
g #=> {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"},
# "20-29"=>{"28"=>"xx", "29"=>"xyz"}}
然后
执行块计算后:
g #=> {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"},
# "20-29"=>{"28"=>"xx", "29"=>"xyz"},
# "40-49"=>{"42"=>"lll", "47"=>"mnx"}}
然后引发一个异常:
key_group,g = e.next
#=> StopIteration (iteration reached an end)
使枚举数返回
g
,因为您的哈希已经按键排序了。slice\u when
,这可能会提高效率;但是,如果散列未排序,则以下解决方案在分组过程中不会受到影响
使用lambda对密钥进行分组:
def group_numeric_range(h, group_size)
groups = ->(n) do
g = n.to_i / group_size
"#{g * group_size + 1}-#{g * group_size + group_size}"
end
h.group_by do |k,_|
groups.(k)
end.transform_values(&:to_h)
end
例如:
h = {"11"=>"a", "12"=>"b", "19"=>"c", "28"=>"xx", "29"=> "xyz",
"42"=>"lll", "47"=>"mnx"}
group_numeric_range(h,10)
#=> {"11-20"=>{"11"=>"a", "12"=>"b", "19"=>"c"}, "21-30"=>{"28"=>"xx", "29"=>"xyz"}, "41-50"=>{"42"=>"lll", "47"=>"mnx"}}
备选方案:
def group_numeric_range(h, group_size)
groups = ->(n) do
g = n.to_i / group_size
"#{g * group_size + 1}-#{g * group_size + group_size}"
end
h.each_with_object(Hash.new{|h,k| h[k] = {}}) do |(k,v),obj|
obj[groups.(k)].merge!(k=>v)
end
end
更新
另一种选择是构建组的数组
,然后选择用于分组的索引(我也添加了输出空范围),例如
它的结果是散列数组,你能把它做成散列数组吗?@code_-aks,我刚刚注意到了这一点并修复了它。谢谢。您可以删除
键
并作为(k1,)、(k2,)
进行计算,然后删除第一个映射
,并将添加到f
(在每个带对象的\u中
)中,这样可以避免由映射引起的键的第二次迭代和额外的一次性数组
。两种解决方案都需要排序h
though@engineersmnky,谢谢你的建议。正如您所建议的,我删除了第一个映射
,但随后选择了另一条路径,试图平衡效率和可读性。@CarySwoveland同上。在这种情况下,我决不会对什么可以归结为一种风格偏好进行质疑。
g #=> {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"},
# "20-29"=>{"28"=>"xx", "29"=>"xyz"}}
key_group,g = e.next
#=> [["42", "47"], {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"},
# "20-29"=>{"28"=>"xx", "29"=>"xyz"}}]
key_group
#=> ["42", "47"]
g #=> {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"},
# "20-29"=>{"28"=>"xx", "29"=>"xyz"}}
g #=> {"10-19"=>{"11"=>"a", "12"=>"b", "19"=>"c"},
# "20-29"=>{"28"=>"xx", "29"=>"xyz"},
# "40-49"=>{"42"=>"lll", "47"=>"mnx"}}
key_group,g = e.next
#=> StopIteration (iteration reached an end)
def group_numeric_range(h, group_size)
groups = ->(n) do
g = n.to_i / group_size
"#{g * group_size + 1}-#{g * group_size + group_size}"
end
h.group_by do |k,_|
groups.(k)
end.transform_values(&:to_h)
end
h = {"11"=>"a", "12"=>"b", "19"=>"c", "28"=>"xx", "29"=> "xyz",
"42"=>"lll", "47"=>"mnx"}
group_numeric_range(h,10)
#=> {"11-20"=>{"11"=>"a", "12"=>"b", "19"=>"c"}, "21-30"=>{"28"=>"xx", "29"=>"xyz"}, "41-50"=>{"42"=>"lll", "47"=>"mnx"}}
def group_numeric_range(h, group_size)
groups = ->(n) do
g = n.to_i / group_size
"#{g * group_size + 1}-#{g * group_size + group_size}"
end
h.each_with_object(Hash.new{|h,k| h[k] = {}}) do |(k,v),obj|
obj[groups.(k)].merge!(k=>v)
end
end
def group_numeric_range(h, group_size)
groups = ((h.keys.max.to_i / group_size) + 1).times.map do |g|
["#{g * group_size + 1}-#{g * group_size + group_size}",{}]
end
h.each_with_object(groups) do |(k,v),obj|
obj[k.to_i / group_size].last.merge!(k=>v)
end.to_h
end
h = {"11"=>"a", "12"=>"b", "19"=>"c", "28"=>"xx", "29"=> "xyz",
"42"=>"lll", "47"=>"mnx"}
group_numeric_range(h,10)
#=> {"1-10"=>{}, "11-20"=>{"11"=>"a", "12"=>"b", "19"=>"c"}, "21-30"=>{"28"=>"xx", "29"=>"xyz"}, "31-40"=>{}, "41-50"=>{"42"=>"lll", "47"=>"mnx"}}