[英]Ruby iterate over an array of hashes
I have the below array of hashes.我有以下哈希数组。 I want to add a new key,value pair to "hashes" which are in "all" array.我想向“所有”数组中的“哈希”添加一个新的键值对。 Is there any better way of looping through, than what I am doing currently?有没有比我目前正在做的更好的循环方式?
stack = {
"all": [
"mango",
"apple",
"banana",
"grapes"
],
"mango": {
"TYPE": "test",
"MAX_SIZE": 50,
"REGION": "us-east-1"
},
"apple": {
"TYPE": "dev",
"MAX_SIZE": 55,
"REGION": "us-east-1"
},
"banana": {
"TYPE": "test",
"MAX_SIZE": 60,
"REGION": "us-east-1"
},
"grapes": {
"TYPE": "dev",
"MAX_SIZE": 80,
"REGION": "us-east-1"
},
"types": [
"dev",
"test"
]
}
My code:我的代码:
stack['all'].each do |fruit|
stack[fruit].each do |fruit_name|
stack[fruit_name]['COUNT'] = stack[fruit_name]['MAX_SIZE'] * 2
end
end
Expected output:预期输出:
stack = {
"all": [
"mango",
"apple",
"banana",
"grapes"
],
"mango": {
"TYPE": "test",
"MAX_SIZE": 50,
"REGION": "us-east-1",
"COUNT" : 100
},
"apple": {
"TYPE": "dev",
"MAX_SIZE": 55,
"REGION": "us-east-1",
"COUNT" : 110
},
"banana": {
"TYPE": "test",
"MAX_SIZE": 60,
"REGION": "us-east-1",
"COUNT" : 120
},
"grapes": {
"TYPE": "dev",
"MAX_SIZE": 80,
"REGION": "us-east-1",
"COUNT" : 160
},
"types": [
"dev",
"test"
]
}
There is no need for the second loop.不需要第二个循环。 The following does what you want:以下是你想要的:
keys = stack[:all].map(&:to_sym)
keys.each do |key|
stack[key][:COUNT] = stack[key][:MAX_SIZE] * 2
end
In the above code-block stack[:all]
will return an array of keys as strings, .map(&:to_sym)
will convert each string in the resulting array into a symbol.在上面的代码块stack[:all]
将返回一个键数组作为字符串, .map(&:to_sym)
将结果数组中的每个字符串转换为一个符号。
Another way to achieve the same result would be to use eitherfetch_values
or values_at
to retrieve an array of values belonging to the provided keys.实现相同结果的另一种方法是使用fetch_values
或values_at
来检索属于提供的键的值数组。 The difference being that fetch_values
raises an exception if a key is missing while values_at
returns nil
for that key.不同之处在于,如果某个键丢失,则fetch_values
会引发异常,而values_at
为该键返回nil
。
fruits = stack.fetch_values(*stack[:all].map(&:to_sym))
fruits.each do |fruit|
fruit[:COUNT] = fruit[:MAX_SIZE] * 2
end
If you are wondering why there is a *
before stack[:all].map(&:to_sym)
, this is to convert the array into individual arguments.如果你想知道为什么在stack[:all].map(&:to_sym)
之前有一个*
,这是为了将数组转换为单独的参数。 In this context *
is called the spat operator .在这种情况下, *
称为spat 运算符。
You might write the code as follows.您可以按如下方式编写代码。
stack[:all].each do |k|
h = stack[k.to_sym]
h[:COUNT] = 2*h[:MAX_SIZE] unless h.nil?
end
When, for example, `k = "mango",例如,当 `k = "mango" 时,
h #=> h={:TYPE=>"test", :MAX_SIZE=>50, :REGION=>"us-east-1", :COUNT=>100}
I've defined the local variable h
for three reasons:我出于三个原因定义了局部变量h
:
stack[k.to_sym]
它通过避免多次引用stack[k.to_sym]
来简化代码h
在调试时,能够检查h
可能会有所帮助Note that h
merely holds an existing hash;请注意, h
仅保存现有的哈希值; it does not create a copy of that hash, so it has a neglibile effect on memory requirements.它不会创建该哈希的副本,因此它对内存需求的影响可以忽略不计。
The technique of defining local variables to hold objects that are parts of other objects is especially useful for more complex objects.定义局部变量以保存属于其他对象的对象的技术对于更复杂的对象尤其有用。 Suppose, for example, we had the hash例如,假设我们有散列
hash = {
cat: { sound: "purr", lives: 9 },
dog: { sound: "woof", toys: ["ball", "rope"] }
}
Now suppose we wish to add a dog toy现在假设我们想添加一个狗玩具
new_toy = "frisbee"
if it is not already present in the array如果它不存在于数组中
hash[:dog][:toys]
We could write我们可以写
hash[:dog][:toys] << new_toy unless hash[:dog][:toys].include?(new_toy)
#=> ["ball", "rope", "frisbee"]
hash
#=> {:cat=>{:sound=>"purr", :lives=>9},
# :dog=>{:sound=>"woof", :toys=>["ball", "rope", "frisbee"]}}
Alternatively, we could write或者,我们可以写
dog_hash = hash[:dog]
#=> {:sound=>"woof", :toys=>["ball", "rope"]}
dog_toys_arr = dog_hash[:toys]
#=> ["ball", "rope"]
dog_toys_arr << new_toy unless dog_toys_arr.include?(new_toy)
#=> ["ball", "rope", "frisbee"]
hash
#=> {:cat=>{:sound=>"purr", :lives=>9},
# :dog=>{:sound=>"woof", :toys=>["ball", "rope", "frisbee"]}}
Not only does the latter snippet display intermediate results, it probably is a wash with the first snippet in terms of execution speed and storage requirements and arguably is more readable.后一个片段不仅显示中间结果,而且在执行速度和存储要求方面可能是第一个片段的清洗,并且可以说更具可读性。 It also cuts down on careless mistakes such as它还减少了粗心的错误,例如
hash[:dog][:toys] << new_toy unless hash[:dog][:toy].include?(new_toy)
If one element of stack[:all]
were, for example, "pineapple"
, stack[:pineapple] #=> nil
since stack
has no key :pineapple
.例如,如果stack[:all]
一个元素是"pineapple"
, stack[:pineapple] #=> nil
因为stack
没有键:pineapple
。 If, however, stack
contained the key-value pair但是,如果stack
包含键值对
nil=>{ sound: "woof", toys: ["ball", "rope"] }
that would become problem.那将成为问题。 Far-fetched?牵强? Maybe, but it is perhaps good practice--in part for readability--to avoid the assumption that h[k] #=> nil
means h
has no key k
;也许吧,但这也许是一种很好的做法——部分是为了可读性——避免假设h[k] #=> nil
意味着h
没有键k
; instead, use if h.key?(k)
.相反,使用if h.key?(k)
。 For example:例如:
stack[:all].each do |k|
key = k.to_sym
if stack.key?(key)
h = stack[key]
h[:COUNT] = 2*h[:MAX_SIZE]
end
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.