[英]Converting Ruby array into a hash
我正在尝试编写一个名为my_transform
的方法,它采用如下数组:
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
并显示项目的索引如下:
item_to_position = {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
我应该能够执行:
my_transform(items) == item_to_position
并收到true
。
我已经考虑使用each_with_index
。 我应该首先说:
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
hash = Hash[*array]
def my_transform
我必须将字符串转换为哈希。 任何帮助表示赞赏。
我会使用Array#to_h
:
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
items.each_with_index.to_h
#=> { "Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4 }
注意to_h
是在 Ruby 2.1 中引入的
使用to_h
您的my_transform
方法可能如下所示:
def my_transform(items)
items.each_with_index.to_h
end
您可以通过多种方式执行此操作。
创建一个数组并将其转换为哈希
直到最近,您还可以使用公共类方法Hash::[]将数组转换为哈希。 它是这样工作的:
h = Hash[ [[:a, 1], [:b, 2]] ]
#=> {:a=>1, :b=>2}
或者
h = Hash[:a, 1, :b, 2]
#=> {:a=>1, :b=>2}
在 Ruby v2.1.0 中引入了Array#to_h和Enumerable#to_h方法。 第一个工作是这样的:
h = [[:a, 1], [:b, 2]].to_h
#=> {:a=>1, :b=>2}
因此,要使用Hash
或to_h
您必须首先创建数组:
arr1 = [["Aqua", 0], ["Blue", 1], ["Green", 2], ["Red", 3], ["Yellow", 4]]
或者
arr2 = ["Aqua", 0, "Blue", 1, "Green", 2, "Red", 3, "Yellow", 4]
在第二种情况下,我们会像这样使用它:
Hash[*arr2]
#=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
让我们首先创建arr1
。 你是对的,你需要使用Enumerable#each_with_index 。 然后,您需要使用Enumerable#to_a将items
每个元素转换为数组[<color>, index]
。
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
arr = items.each_with_index.to_a
#=> [["Aqua", 0], ["Blue", 1], ["Green", 2], ["Red", 3], ["Yellow", 4]]
让我们更仔细地看一下:
enum = items.each_with_index
#=> #<Enumerator: ["Aqua", "Blue", "Green", "Red", "Yellow"]:each_with_index>
enum
是一个枚举器,是类Enumerator 的一个实例。 Enumerator
类是include
Enumerable
模块的众多类之一,其中to_a
是一个实例方法。 不仅:
arr = enum.to_a
#=> [["Aqua", 0], ["Blue", 1], ["Green", 2], ["Red", 3], ["Yellow", 4]]
将枚举数转换为所需的数组,但这是查看任何枚举数(通常传递给块或另一个枚举数)的元素的便捷方式。
所以我们现在可以创建哈希:
h = Hash[arr]
#=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
或者
h = Hash[*arr.flatten]
#=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
或者
h = arr.to_h
#=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
现在假设我们有:
items = ["Aqua", "Blue", "Green", "Aqua", "Aqua"]
然后我们得到:
items.each_with_index.to_a.to_h
#=> {"Aqua"=>4, "Blue"=>1, "Green"=>2}
在构建哈希时,Ruby 首先创建键值对"Aqua"=>0
,然后她用"Aqua"=>3
和"Aqua"=>4
覆盖它。 这是散列具有唯一键这一事实的结果。
从头开始构建哈希
现在假设我们从一个空的哈希开始:
h = {}
(与h = Hash.new
相同)并添加键值对:
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
items.each_index { |i| h[items[i]] = i }
#=> ["Aqua", "Blue", "Green", "Red", "Yellow"]
h #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
我们也可以这样写:
items.size.times { |i| h[items[i]] = i }
#=> 5
h #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
或者
(0...items.size).each { |i| h[items[i]] = i }
#=> 0...5
h #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
Ruby 方法是跳过步骤h = {}
并像以前一样使用each_with_index
和Enumerator#with_object :
items.each_with_index.with_object({}) { |(s,i),h| h[s] = i }
#=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
with_object
的“对象”是一个散列, with_object
的参数是它的初始值,这里是一个空散列。 该对象由块变量h
表示,并在枚举items
所有元素后返回(因此我们不需要后续行h
来返回散列)。
让我们看看这里执行的步骤。 首先,我们有
enum0 = items.each_with_index
#=> #<Enumerator: ["Aqua", "Blue", "Green", "Red", "Yellow"]:each_with_index>
我之前讨论过的。 然后 Ruby 计算
enum1 = enum0.with_object({})
#=> #<Enumerator: #<Enumerator: ["Aqua", "Blue", "Green", "Red", "Yellow"]
:each_with_index>:with_object({})>
仔细检查返回值。 如您所见, enum1
与enum0
一样,是一个枚举器。 您可能会将其视为“复合枚举器”。 要查看将传递给块的enum1
的值,您可以将其转换为数组:
enum1.to_a
#=> [[["Aqua", 0], {}], [["Blue", 1], {}], [["Green", 2], {}],
# [["Red", 3], {}], [["Yellow", 4], {}]]
如您所见, enum1
有五个元素,每个元素都是一个包含一个数组和一个散列的数组。 enum1
的元素由Enumerator#each传递给块,(它调用Array#each ):
enum1.each { |(s,i),h| h[s] = i }
#=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
我们可以使用Enumerator#next将enum1
每个元素enum1
给块,并将块变量设置为其值。 第一个是:
(s,i),h = enum1.next
#=> [["Aqua", 0], {}]
s #=> "Aqua"
i #=> 0
h #=> {}
请注意[["Aqua", 0], {}]
分解为其三个组成元素,并且每个块变量设置为等于其中一个元素。 这称为数组分解。
我们现在可以执行块计算:
h[s] = i
#=> {}["Aqua"] = 0
所以现在:
h #=> {"Aqua"=>0}
然后将第二个元素传递给块:
(s,i),h = enum1.next
#=> [["Blue", 1], {"Aqua"=>0}]
s #=> "Blue"
i #=> 1
h #=> {"Aqua"=>0}
注意h
是如何更新的。 块计算现在是:
h[s] = i
#=> {"Aqua"=>0}["Blue"] = 1
现在:
h #=> {"Aqua"=>0, "Blue"=>1}
其余计算类似。 之后的所有元素enum1
已经列举, enum1.each
返回h
。
def my_transform(arr)
arr.inject({}) {|m,e| m[e] = arr.index(e); m }
end
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
def my_transform(items)
Hash[items.each_with_index.map { |value, index| [value, index] }]
end
你也可以试试这个。
例如
items = ["Aqua", "Blue", "Green", "Red", "Yellow"]
items.inject({}) do |tmphash, (k,v)|
tmphash[k] = items.index(k)
tmphash
end
## OUTPUT
{"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
这至少可以追溯到 Ruby 1.9.3。
# Verbose, but flexible!
def hasherize *array
hash = {}
array.flatten!
array.each_with_index { |key, value| hash[key] = value }
hash
end
# Pass a single array as an argument.
hasherize %w(Aqua Blue Green Red Yellow)
#=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}
# Pass multiple arguments to the method.
hasherize :foo, :bar, :baz
#=> {:foo=>0, :bar=>1, :baz=>2}
如果您运行的是最新的 Ruby,则可以将上述内容简化为:
def hasherize *array
array.flatten.each_with_index.to_h
end
结果将与上面相同,但Array#to_h方法大大简化了代码。 但是,您仍然需要展平数组以避免出现以下结果:
#=> {["Aqua", "Blue", "Green", "Red", "Yellow"]=>0}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.