我有:
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)
]
但仍然没有运气。我正在计算所有括号,并且如错误所示,它在那里,但是我找不到它。顺序重要吗?
答案 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_keys和Hash#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 }