带块的Ruby Hash.new需要深入解释
我正在研究一个名为带块的Ruby Hash.new需要深入解释,ruby,hash,Ruby,Hash,我正在研究一个名为dupped_index的问题的解决方案,但我不太了解这个特定哈希的概念。新变量: def duped_index(arr) result = Hash.new { |hash, key| hash[key] = [] } arr.each_with_index do |ele, idx| result[ele] << idx end result.select { |alphabet, indices| indi
dupped_index
的问题的解决方案,但我不太了解这个特定哈希的概念。新变量:
def duped_index(arr)
result = Hash.new { |hash, key| hash[key] = [] }
arr.each_with_index do |ele, idx|
result[ele] << idx
end
result.select { |alphabet, indices| indices.length > 1 }
end
p duped_index(["a", "b", "c", "c", "b", "b", "c", "d", "b"]) => # {"b"=>[1,4,5,8], "c"=>[2,3,6]}
def dupped_索引(arr)
result=Hash.new{| Hash,key | Hash[key]=[]}
每个带有索引do | ele、idx的阵列|
结果[ele]1}
结束
p重复索引([“a”,“b”,“c”,“c”,“b”,“b”,“c”,“d”,“b”])=>{“b”=>[1,4,5,8],“c”=>[2,3,6]}
你能给我解释一下新块之间发生了什么吗?
总的来说,有没有更有效的方法来解决这个问题呢?新的哈希算法有点令人困惑。哈希的正常行为是,当使用不包含的键访问它时,用nil
响应。“不在书中”。有时这是不够的
当使用哈希尚未拥有的密钥访问哈希时,将运行Hash.new块中的代码。它提供了要使用的参数| h,k |(散列本身和新键)。因此,一个简单的散列可以写成h=Hash.new{h,k | nil}
在这种情况下,当哈希被“询问”第一个字符键“a”时,我们不希望nil
,我们希望在哈希中添加一个新的键“a”,并使用一个空数组作为值,我们可以在其中添加索引。块提供了这一点。TL;博士
默认值是一种为哈希键声明静态或动态值的方法,无需提前显式分配给每个键。实际上,这通常用于确保为所有新键返回一些合理的值,而不需要为创建的每个键指定显式的赋值
代码使用哈希初始化的块形式来设置默认值。我将在下面解释块形式,然后将其与两个更简单的示例进行对比
使用块设置默认值
在Ruby中,可以用多种不同的方式实例化哈希对象。一种方法是通过一个街区到另一个街区。对于没有值的任何键,都将调用此块
考虑以下相关示例:
# define a default value using a block
h = Hash.new { |hash, key| hash[key] = [] }
# block dynamically assigns empty array
# to new keys
h.has_key? 'foo' #=> false
h['foo'] #=> []
h.has_key? 'foo' #=> true
这里,h被分配一个新的散列对象和一个块。此块基本上为未指定显式值的散列的新成员指定一个空数组对象作为“默认值”。实际上,这意味着在查找以前未分配的键时块返回的值将是[]
现在考虑:
h = Hash.new { |hash, key| hash[key] = [] }
# block does nothing for assigned keys
h.has_key? 'bar' #=> false
h['bar'] = nil
h['bar'] #=> nil
h.has_key? 'bar' #=> true
注意赋值(偶数为零)是如何设置期望值的。默认值实际上仅在首次访问不存在的密钥时使用
为什么要用积木?
如果要在运行时计算默认值,或者新键的默认值应该是动态的,则块声明通常更有用。例如:
# define some variable that will change
@foo = 0
# declare a Hash that dynamically calculates
# its default value
h = Hash.new { @foo + 1 }
h['foo'] #=> 1
@foo += 1
h['bar'] #=> 2
# sets default values to `[]` instead of invoking
# a block each time
h = Hash.new []
result = Hash.new do |hash, key|
puts "I just launched the missiles...just kidding"
hash[key] = []
end
但是,除非您需要额外的灵活性,否则您也可以轻松地将数组文本传递给构造函数。例如:
# define some variable that will change
@foo = 0
# declare a Hash that dynamically calculates
# its default value
h = Hash.new { @foo + 1 }
h['foo'] #=> 1
@foo += 1
h['bar'] #=> 2
# sets default values to `[]` instead of invoking
# a block each time
h = Hash.new []
result = Hash.new do |hash, key|
puts "I just launched the missiles...just kidding"
hash[key] = []
end
除非您希望哈希中的不同键的默认值发生变化,否则从语义上讲,将单个对象指定为默认值比指定块更为清晰
另请参见:散列#获取
获得与默认值类似的行为的另一种方法是使用的块形式。例如,给定一个没有默认值的哈希,在执行键查找时仍可以声明默认值:
h = {}
h.fetch 'foo', []
#=> []
#fetch的语义和用例与#new不同,但在像您这样的示例中,实际结果应该是相同的。您采取的方法最终将取决于您试图用代码表达的内容
arr = [1, 2, 1, 3, 2, 1]
您可以编写代码,而无需敲钟或口哨
def duped_index(arr)
result = {}
arr.each_with_index do |ele, idx|
result[ele] = [] unless result.key?(ele)
result[ele] << idx
end
result.select { |ele, indices| indices.length > 1 }
end
另一种方法是根据需要动态创建空数组
def duped_index(arr)
result = {}
arr.each_with_index { |ele, idx| (result[ele] ||= []) << idx }
result.select { |ele, indices| indices.length > 1 }
end
Ruby的解析器将缩写赋值扩展为:
result[ele] = result[ele] || = []
如果result
没有键ele
,result[ele]#=>nil
,那么
result[ele] = nil || = []
#=> []
如果result
有一个键ele
result[ele]
保持不变。所以,
(result[ele] ||= []) << idx
第三种方法是使用默认进程创建哈希,如问题中所述
假设:
result = Hash.new { |hash, key| hash[key] = [] }
#=> {}
现在执行以下操作:
result['dog'] << 'woof'
#=> ["woof"]
result
#=> {"dog"=>["woof"]}
然后执行:
hash['key'] = []
result['dog'] << 'woof'
result
#=> {"dog"=>["woof"]}
导致:
result
#=> { 'dog'=>[] }
然后她执行:
hash['key'] = []
result['dog'] << 'woof'
result
#=> {"dog"=>["woof"]}
result['dog'][“woof”]
行为与之前相同,只是也会显示一条消息。关键是,您可以将任何喜欢的代码放入块中,例如从数据库中提取数据(尽管我不认为这是默认过程的常见用法)
使用这种形式的方法通常写为:
def duped_index(arr)
arr.each_with_index.
with_object(Hash.new { |h,k| h[k]=[] }) { |(ele,idx), result|
result[ele] << idx }.
select { |ele, indices| indices.length > 1 }
end
def dupped_索引(arr)
将每个_与_索引对齐。
使用|对象(Hash.new{| h,k | h[k]=[]}){|(ele,idx),结果|
结果[ele]1}
结束
选择哪种方法主要取决于品味,但我希望大多数红宝石爱好者会选择2或3。其他答案解决了哈希。新的魔法,因此这里有一个最小的解决方案:
def duped_index(list)
list.map.with_index.group_by(&:first).values.select do |l|
l.length > 1
end.map do |l|
l.map(&:last)
end
end
此处list.map.with_index
将列表转换为[[“a”,0],“b”,1],…]
,其中它是一个值和索引对。这由第一个值分组到一个哈希表中,格式为{“a”=>[[“a”,0]],“b”=>[…]}
,其中每对按其第一个条目分组
我们只对分组的值
感兴趣,对于那些要选择的值
那些长度
大于1
的值
过滤后,去掉原始值,只提取每对的最后一个条目,即索引
生产地:
p duped_index(["a", "b", "c", "c", "b", "b", "c", "d", "b"])
# => [[1, 4, 5, 8], [2, 3, 6]]
从文件中:
新的→ 新杂凑
新(obj)→ 新杂凑
新的{散列,键{块}→ 新杂凑
返回一个新的空哈希。如果该散列随后被
与哈希项不对应的键,返回的值
取决于用于创建哈希的new
的样式。首先
窗体,则访问返回
p duped_index(["a", "b", "c", "c", "b", "b", "c", "d", "b"])
# => [[1, 4, 5, 8], [2, 3, 6]]
h = Hash.new("Go Fish")
h["a"] = 100
h["b"] = 200
h["a"] #=> 100
h["c"] #=> "Go Fish"
# The following alters the single default object
h["c"].upcase! #=> "GO FISH"
h["d"] #=> "GO FISH"
h.keys #=> ["a", "b"]
# While this creates a new default object each time
h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
h["c"] #=> "Go Fish: c"
h["c"].upcase! #=> "GO FISH: C"
h["d"] #=> "Go Fish: d"
h.keys #=> ["c", "d"]