在哈希中转换多个数组的智能方法?

时间:2014-01-24 21:34:37

标签: ruby arrays

我需要提示将四个数组转换为哈希值。

我的post params有这四个数组:

"jcrop-x"=>["0", "614", "0", "798"],
"jcrop-y"=>["0", "0", "273", "286"],
"jcrop-x2"=>["717", "666", "678", "482"],
"jcrop-y2"=>["567", "563", "529", "516"],

这是一种矩阵:每个数组的索引为0的值是我main_image的裁剪坐标。第二个值是我square_image等的裁剪坐标

我需要使用这种结构填充数组:

crop_params{
      main_image: {x: 0, y: 0, x2: 717, y2: 567},
      second_image: {x: 614, y: 0, x2: 666, y2: 563},
      third_image: {x: 0, y: 273, x2: 678, y2: 529},
      fourth_image: {x: 798, y: 286, x2: 482, y2: 516} 
}

这是我的实际解决方案:

IMAGE_VERSION = [:main_news_img, :square_img, :vertical_img, :horizontal_img]
crop_params = {}
IMAGE_VERSION.each_with_index do |v,i|
  crop_params[v] = {}
  crop_params[v]["x"] = params['content']["jcrop-x"][i]
  crop_params[v]["y"] = params['content']["jcrop-y"][i]
  crop_params[v]["x2"] = params['content']["jcrop-x2"][i]
  crop_params[v]["y2"] = params['content']["jcrop-y2"][i]
end

我可以用很多行代码来做到这一点。是否有任何聪明的方法可以让我的助手保持清洁和可读?

6 个答案:

答案 0 :(得分:1)

假设您总是有4张图片,请尝试:

Hash[[:main_image, :second_image, :third_image, :fourth_image].zip params.values.transpose.map{|a| Hash[[:x, :y, :x2, :y2].zip(a)]}]

如果不是,则需要稍微修改。

答案 1 :(得分:1)

IMAGE_VERSIONS = [:main_news_img, :square_img, :vertical_img, :horizontal_img]

def map_params(params)
  hashes = params.map do |key, values|
    values.map do |value|
      [key.split('-').last, value.to_i]
    end
  end.transpose.map do |key_value_pairs|
    Hash[key_value_pairs]
  end
  Hash[IMAGE_VERSIONS.zip(hashes)]
end

pp map_params(params)
# => {:main_news_img=>{"x"=>0, "y"=>0, "x2"=>717, "y2"=>567},
# =>  :square_img=>{"x"=>614, "y"=>0, "x2"=>666, "y2"=>563},
# =>  :vertical_img=>{"x"=>0, "y"=>273, "x2"=>678, "y2"=>529},
# =>  :horizontal_img=>{"x"=>798, "y"=>286, "x2"=>482, "y2"=>516}}

答案 2 :(得分:1)

嗯,好吧,我说你的解决方案非常好。以下是另一种方法:

params = {
  "content" => {
    "jcrop-x"=>["0", "614", "0", "798"],
    "jcrop-y"=>["0", "0", "273", "286"],
    "jcrop-x2"=>["717", "666", "678", "482"],
    "jcrop-y2"=>["567", "563", "529", "516"],
  }
}
IMAGE_VERSION = [:main_news_img, :square_img, :vertical_img, :horizontal_img]

IMAGE_VERSION.each_with_index.with_object({}) do |image_and_index, object|
  image_version, i = image_and_index
  object[image_version] = Hash[params['content'].map{|key, value| [key.gsub(/^jcrop-/, ''), value[i]]}]
end

答案 3 :(得分:0)

使用压缩和映射实现您正在寻找的版本:

require 'pp'

params = {
  "jcrop-x"=>["0", "614", "0", "798"],
  "jcrop-y"=>["0", "0", "273", "286"],
  "jcrop-x2"=>["717", "666", "678", "482"],
  "jcrop-y2"=>["567", "563", "529", "516"]
}

# 1. Extract the value arrays, mapping all values to the result
#    of calling .to_i on them:
in_keys = %w{jcrop-x jcrop-y jcrop-x2 jcrop-y2}
in_values = in_keys.map { |key| params[key].map(&:to_i) }

# 2. Now transpose the array of arrays:
in_values_t = in_values.transpose

# 3. Now we have an array of arrays of numbers.  We want this to be
#    an array of hashes instead, so we map them:
out_subkeys = %i{x y x2 y2}
out_values = in_values_t.map { |a| Hash[out_subkeys.zip(a)] }

# 4. Finally, we simply zip that array with the output keys:
out_keys = %i{main_image second_image third_image fourth_image}
crop_params = Hash[out_keys.zip(out_values)]

pp crop_params

答案 4 :(得分:0)

我会这样做:

params = {
  "jcrop-x"  => [  "0", "614",   "0", "798"],
  "jcrop-y"  => [  "0",   "0", "273", "286"],
  "jcrop-x2" => ["717", "666", "678", "482"],
  "jcrop-y2" => ["567", "563", "529", "516"],
}

IMAGE_VERSIONS = [:main_news_img, :square_img, :vertical_img, :horizontal_img]

def map_params(params)
  v = params.map { |key, values| [key.split('-').last, values]}
    # [["x", [  "0", "614",   "0", "798"]],["y" ,[  "0",   "0", "273", "286"]],
    #  ["x2",["717", "666", "678", "482"]],["y2",["567", "563", "529", "516"]]]
  keys, values = [v.map(&:first).map(&:to_sym), v.map(&:last).transpose]
    # keys   => [:x, :y, :x2, :y2]
    # values => [["0",   "0", "717", "567"], ["614",   "0", "666", "563"],
    #            ["0", "273", "678", "529"], ["798", "286", "482", "516"]]
  IMAGE_VERSIONS.each_with_object({}) {|k,h| h[k]=Hash[keys.zip(values.shift)]}
end     
    # { :main_news_img  => {:x=>  "0", :y=>  "0", :x2=>"717", :y2=>"567"},
    #   :square_img     => {:x=>"614", :y=>  "0", :x2=>"666", :y2=>"563"},
    #   :vertical_img   => {:x=>  "0", :y=>"273", :x2=>"678", :y2=>"529"},
    #   :horizontal_img => {:x=>"798", :y=>"286", :x2=>"482", :y2=>"516"} }

如果无法从数据中确定键:x, :y, :x2, :y2,请添加

KEYS = [:x, :y, :x2, :y2]

并将方法简化为:

def map_params(params)
  values = params.map { |_, values| values }.transpose
    # [["0",   "0", "717", "567"], ["614",   "0", "666", "563"],
    #  ["0", "273", "678", "529"], ["798", "286", "482", "516"]]
  IMAGE_VERSIONS.each_with_object({}) {|k,h|h[k]=Hash[KEYS.zip(values.shift)]}
end  

答案 5 :(得分:0)

从一组传入的参数开始,例如:

params = {
  "jcrop-x"  => ["0", "614", "0", "798"],
  "jcrop-y"  => ["0", "0", "273", "286"],
  "jcrop-x2" => ["717", "666", "678", "482"],
  "jcrop-y2" => ["567", "563", "529", "516"],
}

我会用:

transposed_params_values = params.values.transpose
crop_params = Hash[
  *[:main_image, :second_image, :third_image, :fourth_image].flat_map { |k|
    [
      k,
      Hash[
        [:x, :y, :x2, :y2].zip(transposed_params_values.shift)
      ]
    ]
  }
]
# => {:main_image=>{:x=>"0", :y=>"0", :x2=>"717", :y2=>"567"}, :second_image=>{:x=>"614", :y=>"0", :x2=>"666", :y2=>"563"}, :third_image=>{:x=>"0", :y=>"273", :x2=>"678", :y2=>"529"}, :fourth_image=>{:x=>"798", :y=>"286", :x2=>"482", :y2=>"516"}}

或者,写得更紧凑:

transposed_params_values = params.values.transpose
crop_params = Hash[
  *[:main_image, :second_image, :third_image, :fourth_image].flat_map { |k|
    [k, Hash[ [:x, :y, :x2, :y2].zip(transposed_params_values.shift) ]]
  }
]
# => {:main_image=>{:x=>"0", :y=>"0", :x2=>"717", :y2=>"567"}, :second_image=>{:x=>"614", :y=>"0", :x2=>"666", :y2=>"563"}, :third_image=>{:x=>"0", :y=>"273", :x2=>"678", :y2=>"529"}, :fourth_image=>{:x=>"798", :y=>"286", :x2=>"482", :y2=>"516"}}

以下是发生情况的细分:

transposed_params_values = params.values.transpose
# => [["0", "0", "717", "567"], ["614", "0", "666", "563"], ["0", "273", "678", "529"], ["798", "286", "482", "516"]]

Hash[[:x, :y, :x2, :y2].zip(transposed_params_values.first)]
# => {:x=>"0", :y=>"0", :x2=>"717", :y2=>"567"}