【问题标题】:Read multiple hash at a time and update the values in Ruby [closed]一次读取多个哈希并更新 Ruby 中的值 [关闭]
【发布时间】:2017-04-11 11:10:18
【问题描述】:

考虑变量:

ctr = ['cobol',nil,nil,'test',nil,'cobol', nil]

h1 = {
0=>{"ABC"=>"10000100126N", "CDE"=>"2013-08-30-}", "TPP"=>"11400000206633458812N", "APD"=> "01531915972", "PRODUCTID"=>"113n", "OPP"=>"201509n", "CTC"=>"C"}, 
1=>{"ABC"=>"00000039540A", "CDE"=>"0182.22X", "TPP"=>"1234.565N", "APD"=>"12345600", "PRODUCTID"=>"ACHN", "OPP"=>"00000000000119964.1256", "CTC"=>"00000000000211920"}
}

h2 = {'{' => '+0', 'A' => '+1', 'B' => '+2', '}' => '-0', 'N' => '-5'}

任务是读取ctr 数据,其中值为cobol,我们只需对h1 哈希中的这些值应用逻辑。

我们需要解析哈希h1,如果哈希值中的最后一个字符与哈希h2 中的一个键匹配,则将该值替换为相应的值并将符号添加到字符串中。

例如:当我们扫描哈希h1时,对于值“10000100126N”,由于最后一个字符是N并且它存在于h2中,那么输出应该是'-100001001265',其中附加了5并且-是前置。 [不是这个的 ctr 是 'cobol']

但是如果我们查看第二个值“CDE”=>“2013-08-30-}”,因为对于这个键值对,ctr 值不是 cobol,我们对字符串什么都不做。

这是我到目前为止所做的:

h1.each do |k,h|
    h.update(h) do |*, v|
        # puts v
        h2.each do |q,p|
            if (v[-1] == q)
                v.sub!(v[-1], p[-1])
                 v.sub!(/(.*?)/, p[0] +'\1')
            end
        end
        v
    end
end

此代码正在根据要求更新字符串,但它针对h1 中的所有值运行,我只需要为数组ctr 中的值为“cobol”的相应索引运行代码

【问题讨论】:

  • 你有什么问题?
  • @sawa - 如果数组ctr 中的值是'cobol',那么对于哈希h1 中相应元素的值(索引方式)需要进行转换。例如,数组 ctr 中 cobol 的索引是 [0,5] 0 和 5 哈希 h1 中的元素是 'ABC' 和 'OPP',哈希中的相应值应该按照以下逻辑更新:如果最后一个哈希h1中的值的字符存在于哈希h2中,然后将其替换为哈希h2中对应键的值[last char] 例如:10000100126N应更改为-100001001265我需要实现上述。跨度>

标签: arrays ruby ruby-hash


【解决方案1】:

当您将Hash 位置与Array 索引匹配时,首先会出现警告。在您的示例中,['cobol',nil,nil,'test',nil,'cobol', nil] 对应于 h1 的内部 Hash 中的键 ["ABC", "CDE", "TPP", "APD", "PRODUCTID", "OPP", "CTC"]。请记住,Hash 不是基于索引,而是基于键。这意味着,理论上哈希的顺序是不被维护的。一个更好的方法是定义一个Hash,就像这样:{"ABC"=>"cobol", "CDE"=>nil, "TPP"=>nil, "APD"=>"test", "PRODUCTID"=>nil, "OPP"=>"cobol", "CTC"=>nil}

解决了这个警告,让我们来寻找答案。

您正在寻找的是Enumerable#zip 函数,它将每个值与其在ctr 中的对应值结合起来。

[:a, :b, :c].zip([1, 2, 3])
#=> [[:a, 1], [:b, 2], [:c, 3]]

首先我们需要遍历您的哈希,您使用的是Hash#each。由于这是一个转换Enumerable#map 更合适。 map 函数生成一个具有转换值的数组。生成的数组可以转换回具有正确结构的Hash

[[:a, 1], [:b, 2], [:c, 3]].to_h
#=> {:a => 1, :b => 2, :c => 3}

这是我想出的解决方案。它不是最干净的,但它可以工作。

check_logic = lambda do |type, value|
  return value unless type == 'cobol'
  return value unless h2.has_key?(value[-1])
  "#{h2[value[-1]][0]}#{value[0...-1]}#{h2[value[-1]][-1]}"
end


result = h1.map { |k1, v1| [k1, v1.zip(ctr).map { |(k2, v2), type| [k2, check_logic.call(type, v2)] }.to_h] }.to_h
#=> {0=>{"ABC"=>"-100001001265", "CDE"=>"2013-08-30-}", "TPP"=>"11400000206633458812N", "APD"=>"01531915972", "PRODUCTID"=>"113n", "OPP"=>"201509n", "CTC"=>"C"}, 1=>{"ABC"=>"+000000395401", "CDE"=>"0182.22X", "TPP"=>"1234.565N", "APD"=>"12345600", "PRODUCTID"=>"ACHN", "OPP"=>"00000000000119964.1256", "CTC"=>"00000000000211920"}}

如您所见,我使用zipHash 的每个值与ctr Array 组合在一起。我也在使用批量分配(不知道正确的术语)。一个简单的例子是:

(v1, v2, v3) = [1, 2, 3]

导致v1 的值为1v2 的值为2。第二个map有2个参数,第一个是Array,包含内部Hash的键和值,第二个是组合ctrArray的值。通过使用批量赋值,我可以为键和值赋予它们自己的变量名。

由于单行的逻辑有点多,我将其移至 lambda,但这也可能是一个函数(当将 h2 作为参数传递时)。

【讨论】:

    【解决方案2】:

    你试图匹配一个数组和一个哈希,这只会给你带来麻烦。如果您也将ctr 更改为哈希值会更容易:

    ctr = {"ABC" => "cobol", "CDE" => nil, "TPP" => nil, "APD" => "test", "PRODUCTID" => nil, "OPP" => "cobol", "CTC" => nil}
    

    那么至少你可以按键匹配。

    更好的是开始创建一个对象而不是使用你的哈希。一旦你开始将集合对象嵌套这么深,就该创建某种对象来让你的生活更轻松了。

    【讨论】:

    • 我忘了提到对象。很高兴在这里见到他们。
    猜你喜欢
    • 2020-02-21
    • 2014-04-12
    • 2015-09-15
    • 1970-01-01
    • 2022-01-12
    • 2013-07-12
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多