在 Ruby 中找到第一个可能匹配的哈希键的优雅方式

Posted

技术标签:

【中文标题】在 Ruby 中找到第一个可能匹配的哈希键的优雅方式【英文标题】:Elegant way in Ruby to find first of possible matching hash keys 【发布时间】:2016-03-09 21:10:48 【问题描述】:

假设我有可能是这样的用户输入:

input =  user_id: 5, ... 

或者这个:

input =  app_id: 5, ... 

我想返回 :user_id 或 :app_id ,具体取决于提供的内容。我可以这样做:

(input.keys & [:user_id, :app_id]).first

有没有更优雅、更红润、更惯用的方式来做到这一点?

这比上面好还是坏?:

input.slice(:user_id, :app_id).keys.first

(答案不需要严格来自 Ruby 2.2 标准库,也欢迎使用 Rails 方法)

【问题讨论】:

你的已经够优雅了,很有价值的集合交集用例。还是您想要哈希中的 ,而不是键? 不,我想要的是键,而不是值。谢谢。 我可能会亲自做val = input[:user_id] || input[:app_id] @rainkinz 这正是我要问的,不,这不是解决方案。 FWIW Hash#slice 是 Rails 的 ActiveSupport,而不是 Ruby 标准库。 【参考方案1】:

我会使用findhas_key? 反过来解决它:

[:user_id, :app_id].find  |k| input.has_key?(k) 

【讨论】:

我个人认为这不太优雅,而不是更优雅。无论“优雅”是什么意思 :) 这似乎更明确,是的,但不那么简洁。 @Ben 至少分配更少,所以性能应该更高。 @D-side,啊,是的,好点,交叉点创建了一个额外的数组。 我希望 Stefan 这样做是因为它高效且可读性好,而不是因为它优雅。至于是不是“性能”我不能说,因为我的字典里没有这个词。这很有效,因为find 在找到匹配项时会停止查找。 Hash#has_key? 又名 key?include? 效率很高:input.has_key?(k) 最多被调用两次。 The OP's code 创建一个中间数组,其中包含来自input 的所有键,以执行集合交集,这会创建一个临时散列来确定公共元素。 Israveri's code(可能)遍历input 中的每个键/值对,并为input 中的每个键调用KEYS.include?(k)【参考方案2】:

您的解决方案已经足够好了。我更喜欢的替代方案:

input =  app_id: 5, ... 

KEYS = [:app_id, :user_id, :foo_id]

input.find  |key, value| KEYS.include? key 

这样,您可以将您想要的 what 与您想要的 how 分开。您甚至可以从文件中分配 KEYS,这样您甚至不必打开代码即可在查找中添加或删除键。但这可能是过度设计。

我会为KEYS 寻找一个更好的名字。命名很难。

【讨论】:

是的,感谢您的建议。这只是一个简单的示例,用于隔离我要改进的代码。现实世界的代码更复杂,并且确实在 Hash 常量中定义了有效键。我实际构建的是基于 CanCan 和 Pundit 的适配器,因此我可以通过单个界面使用其中任何一个。 我不喜欢这种解决方案,因为对哈希的存在性查找通常更快。但目前的两个答案是一种方法应用于不同方向的一个例子。两个都值得一看。【参考方案3】:

为什么不只是:

input.key?(:user_id) ? :user_id : :app_id

?我错过了什么吗?

【讨论】:

@Ben,我不明白你的意思。您显然可以将它包装在一个参数是两个键的方法中。所有答案都是如此。 我的意思是,如果我们需要扩展这段代码来寻找额外的键,三元结构不再起作用,它不再是两个可能的响应,而这里的一些其他答案将仅按比例缩放向数组中添加另一个元素。 .key?() 采用单个参数,不能是数组,因此在扩展您的解决方案时,除了添加更多 else 子句之外,我看不到任何替代方法。 您的问题非常具体,即存在两个给定键之一。如果它是两个或多个键之一,则需要这样说。就像你问你应该戴红帽还是蓝帽,我回答“红帽”,你说“但是绿帽呢?”。

以上是关于在 Ruby 中找到第一个可能匹配的哈希键的优雅方式的主要内容,如果未能解决你的问题,请参考以下文章

汇总所有相似哈希键的值 Ruby

如何优雅地重命名 Ruby 中哈希中的所有键? [复制]

哈希键的Ruby值?

为啥关键字参数必须作为带有符号键的哈希传递,而不是 Ruby 中的字符串键?

哈希中每个键的不同类型的值

将 json 格式的键值对转换为以符号为键的 ruby​​ 哈希的最佳方法是啥?