将Ruby数组转换为哈希

我正在尝试编写一个名为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} 

因此,要使用Hashto_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每个元素转换为数组[, 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 #=> # 

enum ,枚举器,是枚举器类的一个实例。 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 #=> # 

我之前讨论过。 然后Ruby计算

 enum1 = enum0.with_object({}) #=> #:with_object({})> 

仔细检查返回值。 如您所见, enum1enum0一样,是一个枚举器。 您可能会将其视为“复合枚举器”。 要查看将传递给块的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 

大多数ruby

这至少可以追溯到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> = 2.1.0

如果您正在运行最近的Ruby,则可以将上述内容简化为:

 def hasherize *array array.flatten.each_with_index.to_h end 

结果与上面的结果相同,但Array#to_h方法大大简化了代码。 但是,您仍然需要展平数组以避免以下结果:

 #=> {["Aqua", "Blue", "Green", "Red", "Yellow"]=>0} 

你也可以试试这个。

例如

 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}