如果键存在,向哈希值添加一些东西?

Posted

技术标签:

【中文标题】如果键存在,向哈希值添加一些东西?【英文标题】:Add something to hash value if key exists? 【发布时间】:2014-05-02 02:11:10 【问题描述】:

我在 Ruby 中有一个哈希:

hash = Hash.new

里面有一些键值对,比如:

hash[1] = "One"
hash[2] = "Two"

如果哈希包含一个键2,那么我想将“香蕉”添加到它的值中。如果哈希没有键2,我想创建一个新的键值对2=>"Bananas"

我知道我可以通过首先使用 has_key? 检查哈希是否具有键 2 然后采取相应措施来做到这一点。但这需要if 语句和不止一行。

那么有没有一种简单、优雅的单线来实现这一点?

【问题讨论】:

你写了什么代码来解决这个问题? 一些关于编码的理解:编写只需要一行的代码不是目标。目标是编写“优雅”的代码,这意味着可以理解和强大,而不一定是“简洁”。一个简单的条件和两三行修改是非常好的,如果它是可读的并完成你所需要的。您会发现编程世界充满了您所要求的内容的三行版本,仅仅是因为它可读且同样快速。 Ruby 允许使用分号而不是换行符。您可以将 everything 写在一行中,只需用分号替换换行符即可。问题解决了。 【参考方案1】:

这行得通:

hash[2] = (hash[2] || '') + 'Bananas'

如果您希望所有键都以这种方式运行,您可以使用 Ruby 哈希的“默认”功能:

hash = 
hash.default_proc = proc  '' 
hash[2] += 'Bananas'

【讨论】:

谢谢您或您的回答,我会尽快接受。虽然我不太明白: (hash[2]||'') 部分是什么意思 如果hash[2] 返回一个值,它是“真实的”,它满足||(布尔或)。如果hash[2] 没有值,则返回nil,这是“错误的”,导致|| 触发,并返回""。这就是我在上面评论三行版本更具可读性的确切原因。以这种方式使用布尔逻辑是我们以可读性为代价使用的一种高级技术。 带有可变对象的default= 方法是一个等待发生的错误:hash[3]<<"pinapple"; p h[4] #=>"pineapple" @sttenslag,你是对的。我将答案改为使用default_proc,这样您每次都会生成一个新字符串。另一个有趣的选项是hash.default = ''.freeze 对于那些不阅读 cmets 的人来说,为什么使用 default_proc= 而不是 default= 可能值得添加答案。【参考方案2】:
(hash[2] ||= "").concat("Bananas")

【讨论】:

<< 只是 concat 的别名 @p11y 他们也有不同之处..但这不是重点.. :) @ArupRakshit 无法想象会有什么不同,因为两者都在内部调用rb_str_concat。真的只是一个别名 但是你展示的是一个数组,而不是一个字符串。在 Array 类上,<<push 的别名。令人困惑,我承认。在这里,我们对一个字符串进行操作。 @ArupRakshit 那么我必须再次不同意 :) 在 String 类上 <<concat 的别名。在 Array 类上,<<push 的别名。仅仅因为这些方法具有相同的名称并不意味着它们之间有任何关系。【参考方案3】:

您可以将散列的默认值设置为空字符串,然后使用

h = Hash.new("")
#=> 
h[2] << "Bananas"
#=> "Bananas" 
h
#=> 2=>"Bananas" 
h[2] << "Bananas"
#=> "BananasBananas" 

根据@rodrigo.garcia 的评论,这种方法的另一个副作用是Hash.new() 设置了哈希的默认返回值(可能是也可能不是您想要的)。在上面的示例中,该默认值是一个空字符串,但它不一定是:

h2 = Hash.new(2)
#=> 
h2[5] 
#=> 2

【讨论】:

a += b,等同于a = a + b 效率低于&lt;&lt;concat,因为它创建了字符串的副本。其他人将“真正”附加到现有字符串。除此之外,我认为您的解决方案是最好的:) 啊,是的,这很好。感谢您的评论,我已经更新了我的答案。 使用Hash.new(x) 将始终返回相同的实例x 作为默认值。由于在这里您通过将"Bananas" 连接到它两次来修改"",现在每个未设置的键都将返回"BananasBananas"(例如尝试执行h[4])。在某些情况下,这可能是所需的行为,但您应该在回答中解释它。 @rodrigo.garcia - 添加了注释。【参考方案4】:

从技术上讲,你的两条路都通向同一个地方。所以Hash[2] = "bananas" 产生的结果与首先检查密钥 2 的哈希值相同。但是,如果您出于某种原因确实需要检查哈希值的过程,则可以使用.has_key? 方法和基本的@987654323 @有条件的。

假设有一个哈希,

`Hash =  1 => "One", 2 => "Two" `

根据关键字搜索的真值设置代码块,

if hash.has_key?(2) == true hash[2] = "bananas" else hash[2] = "bananas" end

或更简单地说,

hash.has_key?(2) == true ? hash[2] = "bananas" : hash[2] = "bananas"

【讨论】:

【参考方案5】:

你可以用一个块初始化哈希,然后直接连接:

hash = Hash.new |hash, key| hash[key] = ""
hash[1] << "One"
hash[2] << "Two"
hash[2] << "Bananas"

1=>"One", 2=>"TwoBananas"

【讨论】:

以上是关于如果键存在,向哈希值添加一些东西?的主要内容,如果未能解决你的问题,请参考以下文章

如果密钥存在,添加一些哈希值?

在检索值之前检查哈希映射键是不是存在[重复]

如果值相同,则连接哈希键,如果键相同,则连接哈希值

Redis学习笔记09Redis数据类型之 哈希表类型

我想通过键创建一个组哈希并添加值

705.设计哈希集合