根据所有文档,您可以使用<<
或.push
或+=
将元素附加到数组,结果应该相同。我发现不是。有人可以向我解释我错了吗? (我使用的是Ruby 2.3.1。)
我有很多哈希。它们都包含相同的密钥。我想将它们结合在一起,以一个数组中的所有收集值形成一个哈希。这很简单,您遍历所有哈希并创建一个新哈希,收集所有值,如下所示:
# arg is array of Hashes - keys must be identical
return {} unless arg
keys = (arg[0] ? arg[0].keys : [])
result = keys.product([[]]).to_h # value for each key is empty array.
arg.each do |h|
h.each { |k,v| result[k] += [v] }
end
result
end
如果我使用+=
或.push
而不是使用<<
而不是,则会得到完全奇怪的结果。
使用以下测试数组:
a_of_h = [{"1"=>10, "2"=>10, "3"=>10, "4"=>10, "5"=>10, "6"=>10, "7"=>10, "8"=>10, "9"=>10, "10"=>10}, {"1"=>100, "2"=>100, "3"=>100, "4"=>100, "5"=>100, "6"=>100, "7"=>100, "8"=>100, "9"=>100, "10"=>100}, {"1"=>1000, "2"=>1000, "3"=>1000, "4"=>1000, "5"=>1000, "6"=>1000, "7"=>1000, "8"=>1000, "9"=>1000, "10"=>1000}, {"1"=>10000, "2"=>10000, "3"=>10000, "4"=>10000, "5"=>10000, "6"=>10000, "7"=>10000, "8"=>10000, "9"=>10000, "10"=>10000}]
我明白了
merge_hashes(a_of_h)
=> {"1"=>[10, 100, 1000, 10000], "2"=>[10, 100, 1000, 10000], "3"=>[10, 100, 1000, 10000], "4"=>[10, 100, 1000, 10000], "5"=>[10, 100, 1000, 10000], "6"=>[10, 100, 1000, 10000], "7"=>[10, 100, 1000, 10000], "8"=>[10, 100, 1000, 10000], "9"=>[10, 100, 1000, 10000], "10"=>[10, 100, 1000, 10000]}
如我所料,但是如果我使用h.each { |k,v| result[k] << v }
,我会得到
buggy_merge_hashes(a_of_h)
=> {"1"=>[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000], "2"=>[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000], "3"=>[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000], "4"=>[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000], "5"=>[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000], ...}
(剩下的我都剪掉了。)
我在这里不知道什么?
答案 0 :(得分:1)
<<
和#push
是破坏性操作(它们会更改接收方)。
+
(因此也+=
)是一种非破坏性操作(它返回一个新对象,而接收方保持不变)。
虽然他们似乎在做同一件事,但这种细微的差别至关重要。
这是由于另一个错误而引起的:result
中的所有子数组都从同一对象开始。如果您要添加其中一个,则要添加所有它们。
如果您使用+=
,为什么这不是问题?因为result[k] += [v]
与result[k] = result[k] += [v]
是相同的(我躺在这里,有细微的差别,但这在这里并不重要,只是接受它们现在是相同的,不要感到困惑: D);并且由于+
是非破坏性的,因此result[k] + [v]
是与result[k]
不同的对象;当您通过此分配更新数组中的值时,就不再使用起始[]
对象,并且引用共享错误也无法再对您造成伤害。
创建result
数组的更好方法是以下方法之一:
result = Array.new(keys.size) { [] }
result = keys.map { [] }
这将为每个元素创建一个新的数组对象。
但是,我会写得完全不同:
a_of_h.each_with_object(Hash.new { |h, k| h[k] = [] }) { |h, r|
h.each { |k, v| r[k] << v }
}
each_with_hash
将传递的对象作为附加参数提供给块(此处为r
,以获取结果),并在方法完成后返回。参数-将位于r
中的对象-将是带有default_proc
的哈希值:每当我们尝试获取尚未在其中的键时,它将在其中插入一个新数组(即,尝试预先填充我们的结果对象,请按需进行)。然后,我们只需遍历数组中的每个哈希,然后将值插入结果哈希即可,而不必担心键是否存在。
答案 1 :(得分:0)
第一个执行var timeZone : String = String()
override func viewDidLoad() {
super.viewDidLoad()
timeZone = getCurrentTimeZone()
print(timeZone)
}
func getCurrentTimeZone() -> String {
let localTimeZoneAbbreviation: Int = TimeZone.current.secondsFromGMT()
let items = (localTimeZoneAbbreviation / 3600)
return "\(items)"
}
。第二个是hash[key] += value
。