如果哈希键满足条件,则使用ruby do语句

时间:2019-01-21 20:57:30

标签: ruby hashmap

我有:

event = {"first_type_a" => 100, "first_type_b" => false, "second_type_a" => "abc", "second_type_b" => false}

我正在尝试基于原始密钥更改event的键。如果名称包含子字符串,则名称将被更改,并应添加新的密钥,对值,而旧的对应被删除。我希望得到:

event = {"important.a_1" => 100, "important.b_1" => false, "second_type_a" => "abc", "second_type_b" => false}

更新event的最有效方法是什么?

我希望它能起作用:

event.each_pair { |k, v|
  if !!(/first_type_*/  =~ k) do
        key = "#{["important", k.split("_", 3)[2]].join(".")}";
        event.merge!(key: v);
        event.delete(k)  
  end
}

但是会引发错误:

  simpleLoop.rb:5: syntax error, unexpected keyword_do, expecting keyword_then or ';' or '\n'
  ... if !!(/first_type_*/  =~ k) do
  ...                             ^~
  simpleLoop.rb:9: syntax error, unexpected keyword_end, expecting '}'
    end
    ^~~
  simpleLoop.rb:21: embedded document meets end of file

我想以不同的方式处理它:

if result = event.keys.find { |k| k.include? "first_type_" } [
  key = "#{["important", k.split("_", 3)[2]].join(".")}"
  event.merge!(key: v)
  event.delete(k)
]

但仍然没有运气。我正在计算所有括号,并且如错误所示,它在那里,但是我找不到它。顺序重要吗?

3 个答案:

答案 0 :(得分:1)

if开始一个块,例如其他结构if ... else ... end do ... end begin ... rescue ... end

因此,您的第一个示例在do之后删除if,该块已打开。我还通过将each_pair之后的块更改为使用do ... end而不是花括号来使其更清晰,以防止哈希与块混淆。

event = { 'first_type_a' => 100, 'first_type_b' => false, 'second_type_a' => 'abc', 'second_type_b' => false }
new_event = {}
event.each_pair do |k, v|
  if !!(/first_type_*/  =~ k)
    important_key = ['important', k.split('_', 3)[2]].join('.')
    new_event[important_key] = v
  else
    new_event[k] = v
  end
end

答案 1 :(得分:1)

我将展示如何在Ruby中非常经济地完成此操作。直到最近,当想要修改哈希键时,通常会做以下两件事之一:

  • 创建一个新的空哈希,然后将键/值对添加到哈希;或
  • 将散列转换为具有两个元素的数组(键-值对)的数组a,修改a的每个元素的第一个元素(键),然后转换{{1} }到所需的哈希值。

最近(使用MRI v2.4),Ruby僧侣为我们提供了方便的方法Hash#transform_keysHash#transform_keys!。我们可以在这里有利可图地使用其中的第一个。首先,我们需要一个正则表达式来匹配键。

a

通常是这样写的

r = /
    \A           # match beginning of string
    first_type_  # match string
    (\p{Lower}+) # match 1+ lowercase letters in capture group 1
    \z           # match the end of the string
    /x           # free-spacing regex definition mode

使用自由行距模式使正则表达式具有自记录功能。现在,我们将r = /\Afirst_type_(\p{Lower}+)\z/ 方法与方法String#sub和刚刚定义的正则表达式一起应用。

transform_keys

在正则表达式中,可以将 p {}构造表达式event = {"first_type_a"=>100, "first_type_b"=>false, "second_type_a"=>"abc", "second_type_b"=>false} event.transform_keys { |k| k.sub(r, "important.#{'\1'}_1") } #=> {"important.a_1"=>100, "important.b_1"=>false, # "second_type_a"=>"abc", "second_type_b"=>false} 替换为\p{Lower},即 POSIX括号表达式 \p{L} (两个都匹配Unicode字母)或[[:lower:]],但最后一个缺点是它不匹配带有变音符号的字母。其中包括从其他语言中借来的英文单词中使用的单词字母(例如桃红,葡萄酒)。在Regexp中搜索POSIX和[a-z]表达式的文档。

如果\p{}后可以是小写或大写字母,请使用"first_type_";如果后面可以跟字母数字字符,请使用\p{Alpha},依此类推。

答案 2 :(得分:1)

您可以定义在转换键调用中使用的方法:

def transform(str)
  return ['important.', str.split('_').last, '_1'].join() if str[0..4] == 'first' # I checked just for "first"
  str
end

event.transform_keys! { |k| transform(k) } # Ruby >= 2.5 
event.map { |k, v| [transform(k), v] }.to_h # Ruby < 2.5 

使用Hash#each_pair,但使用Enumerable#each_with_object

event.each_pair.with_object({}) { |(k, v), h| h[transform(k)] = v }

或用作一种衬纸:

event.transform_keys { |str| str[0..4] == 'first' ? ['important.', str.split('_').last, '_1'].join() : str  }