Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 在ruby中从排列好的散列中切块_Ruby On Rails_Ruby - Fatal编程技术网

Ruby on rails 在ruby中从排列好的散列中切块

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

我有一个散列,其中键是按排序顺序排列的,散列大小超过1000。如何根据范围将哈希划分为块

示例:-

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"}}