Ruby Hash是å¦ä¿ç•™ä¸€ä¸ªå•ç‹¬çš„读å–值列表与指定的值?

时间:2017-04-30 08:10:49

标签: ruby dictionary hashtable

这与Ruby hash default value behavior

有关

但也许那里的解释ä¸åŒ…括这一部分:看æ¥Rubyçš„Hash默认值是独立的,无论你是“读它â€ï¼Œè¿˜æ˜¯çœ‹â€œè®¾ç½®ä»€ä¹ˆâ€ï¼Ÿ

一个例å­æ˜¯ï¼š

foo = Hash.new([])

foo[123].push("hi")

p foo       # => {}
p foo[123]  # => ["hi"]
p foo       # => {}

foo[123]如何有一个值,但是foo都是空的,有点超出我的ç†è§£......我能ç†è§£çš„唯一方法是Ruby Hashä¿ç•™ä¸€ä¸ªå•ç‹¬çš„列表“读â€æˆ–“å¸æ°”â€ï¼Œä½†ä¸çŸ¥ä½•æ•…,“内部â€æŒ‡å®šå€¼æ˜¯ä¸åŒçš„。

如果Ruby的设计原则之一是“给程åºå‘˜å¸¦æ¥æœ€å°‘的惊喜â€ï¼Œé‚£ä¹ˆfoo是空的,但foo[123]是æŸç§ä¸œè¥¿ï¼Œåœ¨æŸç§ç¨‹åº¦ä¸Šæ˜¯è¿™æ ·çš„,对于我

(实际上我还没有看到其他语言...如果有其他语言有类似行为的情况,也许更容易建立è”系。)

4 个答案:

答案 0 :(得分:3)

å‡è®¾`

h = Hash.new(:cat)
h[:a] = 1
h[:b] = 2
h #=> {:a=>1, :b=>2}

现在

h[:a] #=> 1
h[:b] #=> 2
h[:c] #=> :cat
h[:d] #=> :cat
h     #=> {:a=>1, :b=>2}

h = Hash.new(:cat)使用h的默认值定义空哈希:cat。这æ„味ç€ï¼Œå¦‚æžœh没有密钥k,则h[k]将返回:cat,仅返回。如上所示,当h[k]为k或:c时,执行:dä¸ä¼šæ›´æ”¹å“ˆå¸Œå€¼ã€‚

å¦ä¸€æ–¹é¢ï¼Œ

h[:c] = h[:c]
  #=> :c
h #=> {:a=>1, :b=>2, :c=>:cat}

困惑?让我在没有语法糖的情况下写这个:

h.[]=(:d, h.[](:d))
  #=> :cat
h #=> {:a=>1, :b=>2, :d=>:cat}

默认值由h.[](:d)返回(å³h[:d]),而Hash#[]=是一个赋值方法(带有两个å‚数,一个键和一个值),默认值为ä¸é€‚用。

此默认设置的常è§ç”¨æ³•æ˜¯åˆ›å»ºè®¡ç®—哈希:

a = [1,3,1,4,2,5,4,4]
h = Hash.new(0)
a.each { |x| h[x] = h[x] + 1 }
h #=> {1=>2, 3=>1, 4=>3, 2=>1, 5=>1}

最åˆï¼Œå½“h为空且x #=> 1时,h[1] = h[1] + 1将评估为h[1] = 0 + 1,因为(因为h没有密钥1 )等å¼å³ä¾§çš„h[1]设置为等于默认值零。下次1传递给å—x #=> 1),x[1] = x[1] + 1,等于x[1] = 1 + 1。这次没有使用默认值,因为h现在有一个键1。

通常会写(顺便说一å¥ï¼‰ï¼š

a.each_with_object(Hash.new(0)) { |x,h| h[x] += 1 }
  #=> {1=>2, 3=>1, 4=>3, 2=>1, 5=>1}

通常ä¸å¸Œæœ›é»˜è®¤å€¼æ˜¯é›†åˆï¼Œä¾‹å¦‚数组或散列。请考虑以下事项:

h = Hash.new([])
[1,2,3].map { |n| h[n] = h[n] }
h #=> {1=>[], 2=>[], 3=>[]}

现在观察:

h[1] << 2
h #=> {1=>[2], 2=>[2], 3=>[2]}

这通常ä¸æ˜¯ç†æƒ³çš„行为。它å‘生了,因为

h.map { |k,v| v.object_id }
  #=> [25886508, 25886508, 25886508]

也就是说,所有值都是åŒä¸€ä¸ªå¯¹è±¡ï¼Œå› æ­¤å¦‚果更改了一个键的值,则所有其他键的值也会更改。

解决这个问题的方法是在定义哈希时使用å—:

h = Hash.new { |h,k| h[k]=[] }
[1,2,3].each { |n| h[n] = h[n] }
h #=> {1=>[], 2=>[], 3=>[]}
h[1] << 2
h #=> {1=>[2], 2=>[], 3=>[]}
h.map { |k,v| v.object_id }
  #=> [24172884, 24172872, 24172848]

当散列h没有键k时,å—{ |h,k| h[k]=[] }被执行并返回一个特定于该键的空数组。

答案 1 :(得分:2)

声明:

foo = Hash.new([])

creates a new Hash,其数组为空([]为默认值)。默认值是Hash::[]在其å‚æ•°ä¸æ˜¯æ•£åˆ—中存在的键时返回的值。

声明:

foo[123]

调用Hash::[],因为哈希是空的(哈希中ä¸å­˜åœ¨é”®123),它返回对默认值的引用,该默认值是{{3}类型的对象}。 上é¢çš„语å¥ä¸ä¼šåœ¨å“ˆå¸Œä¸­åˆ›å»º123键。

Ruby对象总是通过引用传递和返回。这æ„味ç€ä¸Šé¢çš„语å¥ä¸ä¼šè¿”回散列的默认值的副本,而是返回对它的引用。

声明:

foo[123].push("hi")

修改上é¢æ到的数组。现在,foo哈希的默认值ä¸å†æ˜¯ç©ºæ•°ç»„;它是数组["hi"]。但是ä»ç„¶æ˜¯ç©ºçš„;以上所有语å¥éƒ½æ²¡æœ‰æ·»åŠ ä¸€äº›ï¼ˆé”®ï¼Œå€¼ï¼‰å¯¹ã€‚

  

foo [123]如何具有值

foo[123]没有任何值,哈希中ä¸å­˜åœ¨é”®123(哈希为空)。éšåŽå¯¹foo[123]的调用会å†æ¬¡è¿”回对默认值的引用,现在返回默认值["hi"]。对foo[456]或foo['abc']的调用也会返回对相åŒé»˜è®¤å€¼çš„引用。

答案 2 :(得分:0)

您实际上并未更改密钥123的值,您åªæ˜¯è®¿é—®åˆå§‹åŒ–期间æ供的默认值[]。如果您检查foo[0]等其他值,则å¯ä»¥ç¡®è®¤è¿™ä¸€ç‚¹ã€‚

如果你这样åšï¼š

foo[123] = ["hi"]

您å¯ä»¥çœ‹åˆ°æ–°æ¡ç›®ï¼Œå› ä¸ºæ‚¨å·²åœ¨å¯†é’¥123下创建了一个新数组。

修改的

  • 当您致电foo[123].push("hi")时,您改å˜ï¼ˆé»˜è®¤ï¼‰å€¼ï¼Œè€Œä¸æ˜¯æ·»åŠ æ–°æ¡ç›®ã€‚

  • 调用foo[123] += ["hi"] 会在给定密钥下创建一个新数组,替æ¢ä¹‹å‰å­˜åœ¨çš„数组,这将显示您想è¦çš„行为。

答案 3 :(得分:0)

打å°å“ˆå¸Œï¼š

p foo

仅打å°å­˜å‚¨åœ¨å“ˆå¸Œä¸­çš„值。它ä¸æ˜¾ç¤ºé»˜è®¤å€¼ï¼ˆæˆ–添加到默认数组的任何内容)。

执行时:

p foo[123]

因为123ä¸å­˜åœ¨ï¼Œæ‰€ä»¥å®ƒè®¿é—®é»˜è®¤å€¼ã€‚

如果您将两个值添加到默认值:

foo[123].push("hi")
foo[456].push("hello")

您的输出将是:

p foo       # => {}
p foo[123]  # => ["hi","hello"]
p foo       # => {}

这里,poo [123]å†æ¬¡ä¸å­˜åœ¨ï¼Œæ‰€ä»¥å®ƒæ‰“å°å‡ºé»˜è®¤å€¼çš„内容。