【问题标题】:Ruby Hash Whitelist FilterRuby 哈希白名单过滤器
【发布时间】:2010-10-17 05:55:09
【问题描述】:

我试图弄清楚如何将键和值对从一个过滤器过滤到另一个过滤器中

例如我想取这个哈希

x = { "one" => "one", "two" => "two", "three" => "three"}

y = x.some_function

y == { "one" => "one", "two" => "two"}

感谢您的帮助

编辑:可能应该提到,在这个例子中,我希望它充当白名单过滤器。也就是说,我知道我想要什么,而不是我不想要什么。

【问题讨论】:

标签: ruby hashmap


【解决方案1】:

您可以只使用内置的哈希函数拒绝。

x = { "one" => "one", "two" => "two", "three" => "three"}
y = x.reject {|key,value| key == "three" }
y == { "one" => "one", "two" => "two"}

您可以将任何您想要的逻辑放入拒绝,如果块返回 true,它将跳过新哈希中的键、值。

【讨论】:

  • 打字落后 5 秒...我知道我应该在测试前发布以确保我没有打错字。
  • 你可以使用reject!而不是设置另一个变量
  • @Radar 破坏性修饰符可能会导致问题,例如,如果哈希作为参数传递给方法并且调用者不希望哈希被该方法修改。最好养成进行非破坏性更新的习惯,只在必要时使用破坏性操作符。
  • 这很好但是我可能不知道其他哈希键。我只知道我想要的那些
  • 投反对票,因为这是一个黑名单过滤器,但 OP 想要一个白名单。
【解决方案2】:
y = x.reject {|k,v| k == "three"}

【讨论】:

    【解决方案3】:

    也许这就是你想要的。

    wanted_keys = %w[one two]
    x = { "one" => "one", "two" => "two", "three" => "three"}
    x.select { |key,_| wanted_keys.include? key }
    

    包含在例如 Enumerable mixin 中。 Array 和 Hash 提供了很多有用的方法,例如 select/reject/each/etc.. 我建议您使用 ri Enumerable 查看它的文档。

    【讨论】:

    • 但是 select 方法返回一个数组。在这种情况下,我需要一个哈希
    • 对于 1.8.7 使用 reject 并否定条件
    【解决方案4】:

    结合大家的答案,我想出了这个解决方案:

     wanted_keys = %w[one two]
     x = { "one" => "one", "two" => "two", "three" => "three"}
     x.reject { |key,_| !wanted_keys.include? key }
     =>{ "one" => "one", "two" => "two"}
    

    感谢你们的帮助!

    编辑:

    以上适用于 1.8.7+

    以下适用于 1.9+ :

    x.select { |key,_| Wanted_keys.include?键}

    【讨论】:

    • 为什么要双重否定? x.select { |key,_| wanted_keys.include? key }?这会为我返回一个哈希
    • 这取决于您使用的 ruby​​ 版本。这适用于 1.9+,但不适用于 1.8.7。我会编辑答案
    • 拒绝接受您自己的@sris 答案副本!您对该答案的评论足以指出差异。
    • @RobinGower 我在 5 年前选择了这个答案,当时,这是正确的答案。当我发表评论时,1.8.7 仍在广泛使用中,这仍然是正确的答案。我现在可以更改它,但没有必要投反对票。
    • 啊 - 我明白了,那条评论是几年后出现的。抱歉,我的投票已锁定,因此我无法取消投票。
    【解决方案5】:

    Rails 的 ActiveSupport 库还为您提供切片,除了在关键级别处理哈希:

    y = x.slice("one", "two") # => { "one" => "one", "two" => "two" }
    y = x.except("three")     # => { "one" => "one", "two" => "two" }
    x.slice!("one", "two")    # x is now { "one" => "one", "two" => "two" }
    

    这些都很好,我一直在使用它们。

    【讨论】:

    • 如果 x 是一个 ActiveRecord::Base 子类,你可以这样做y = x.attributes.slice *%w(one two three)
    • 如果你熟悉_.pick in Underscore.js,这也是同样的想法。 (我是来找那个的!)
    • 而且ActiveSupport 非常轻量级,它被许多非Rails gem 使用。
    • 嘘!正是我需要的
    • 如果您在 sris 的回答中有一系列属性,例如 wanted_keys,您可以使用 y = x.slice(*wanted_keys)
    【解决方案6】:

    改进一点@scottd 的答案,如果您正在使用rails 并且有一个您需要的列表,您可以将列表扩展为切片中的参数。例如

    hash = { "one" => "one", "two" => "two", "three" => "three"}
    keys_whitelist = %W(one two)
    hash.slice(*keys_whitelist)
    

    如果没有 rails,对于任何 ruby​​ 版本,您都可以执行以下操作:

    hash = { "one" => "one", "two" => "two", "three" => "three"}
    keys_whitelist = %W(one two)
    Hash[hash.find_all{|k,v| keys_whitelist.include?(k)}] 
    

    【讨论】:

    • 请注意,您不一定需要使用 Rails,您只需加载 Active Support。将 active_support 添加到您的 Gemfile 和 require "active_support/core_ext/hash/slice"
    • find_allselect 的别名,所以这与前两个答案基本相同:-)
    【解决方案7】:

    我会使用 lambda 进行过滤。这将允许您编写复杂的过滤逻辑并使其易于测试。提取过滤逻辑的事实将允许在其他上下文中重用它。

    例如:

    x = { "one" => "one", "two" => "two", "three" => "three"}
    
    matcher = ->(key,value) { 
      # FILTERING LOGIC HERE 
       !key[/three/]
    }
    
    x.select(&matcher) == { "one" => "one", "two" => "two"}
    

    【讨论】:

      猜你喜欢
      • 2015-09-18
      • 2011-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-14
      • 2016-05-19
      • 2018-08-26
      • 1970-01-01
      相关资源
      最近更新 更多