在 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】:
我会使用find
和has_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 中找到第一个可能匹配的哈希键的优雅方式的主要内容,如果未能解决你的问题,请参考以下文章