代码之家  ›  专栏  ›  技术社区  ›  tomasz74

如果哈希键满足条件,则返回ruby do语句

  •  0
  • tomasz74  · 技术社区  · 6 年前

    我有:

    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.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 回复  |  直到 6 年前
        1
  •  1
  •   Cary Swoveland    6 年前

    我将展示如何在Ruby中实现这一点。直到最近,当想要修改哈希的键时,通常需要做两件事之一:

    • 创建新的空哈希,然后向哈希中添加键/值对;或
    • 将哈希转换为数组 a 在两个元素数组(键值对)中,修改 (键)然后转换 到所需的哈希。

    最近(核磁共振2.4版),红宝石僧侣给了我们方便的方法 Hash#transform_keys Hash#transform_keys! . 我们可以在这里利用第一个。首先,我们需要一个正则表达式来匹配键。

    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/
    

    使用 自由间距模式 使regex自动记录。我们现在应用 transform_keys 方法,连同方法 String#sub 和刚刚定义的正则表达式。

    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{}构造 表达 \p{Lower} 可替换为 \p{L} , the POSIX括号表达式 [[:lower:]] (两者都匹配Unicode字母)或 [a-z] 但最后一个缺点是,它不匹配带有发音标记的字母。其中包括从英语文本中使用的其他语言中借用的单词字母(如“葡萄酒”)。搜索 Regexp 对于POSIX和 \p{} 表达。

    如果 "first_type_" 可以后跟小写或大写字母use \p{Alpha} ;如果后面可以跟字母数字字符,请使用 \p{Alnum} 等等。

        2
  •  1
  •   BookOfGreg    6 年前

    这个 if 启动块,如其他结构 if ... else ... end do ... end begin ... rescue ... end

    因此,您的第一个示例移除 do 如果 ,块已打开。我也通过改变后的街区使它更清晰 each_pair 使用 做…结束 而不是大括号来帮助避免将哈希与块混淆。

    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
    
        3
  •  1
  •   iGian    6 年前

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

    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  }