简体   繁体   English

将 Ruby 数组转换为哈希

[英]Converting Ruby array into a hash

I am attempting to write a method named my_transform that takes an array as follows:我正在尝试编写一个名为my_transform的方法,它采用如下数组:

items = ["Aqua", "Blue", "Green", "Red", "Yellow"]

and displays the items' indexes as follows:并显示项目的索引如下:

item_to_position = {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}

I should be able to execute:我应该能够执行:

my_transform(items) == item_to_position

and receive true .并收到true

I have contemplated using each_with_index .我已经考虑使用each_with_index Should I begin by saying:我应该首先说:

items = ["Aqua", "Blue", "Green", "Red", "Yellow"]

hash = Hash[*array]

def my_transform

I have to convert the string to a hash.我必须将字符串转换为哈希。 Any help is appreciated.任何帮助表示赞赏。

I would use Array#to_h :我会使用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 }

Note that to_h was introduced in Ruby 2.1注意to_h是在 Ruby 2.1 中引入的

Using to_h your my_transform method could look like this:使用to_h您的my_transform方法可能如下所示:

def my_transform(items)
  items.each_with_index.to_h
end

You can do this in various ways.您可以通过多种方式执行此操作。

Create an array and convert it to a hash创建一个数组并将其转换为哈希

Until fairly recently, you would use the public class method Hash::[] to convert an array to a hash.直到最近,您还可以使用公共类方法Hash::[]将数组转换为哈希。 It works like this:它是这样工作的:

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

or或者

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

In Ruby v2.1.0 the methods Array#to_h and Enumerable#to_h were introduced.在 Ruby v2.1.0 中引入了Array#to_hEnumerable#to_h方法。 The first works like this:第一个工作是这样的:

h = [[:a, 1], [:b, 2]].to_h
  #=> {:a=>1, :b=>2}

Therefore, to use Hash or to_h you must first create the array:因此,要使用Hashto_h您必须首先创建数组:

arr1 = [["Aqua", 0], ["Blue", 1], ["Green", 2], ["Red", 3], ["Yellow", 4]]

or或者

arr2 = ["Aqua", 0, "Blue", 1, "Green", 2, "Red", 3, "Yellow", 4]

In the second case we'd use it like this:在第二种情况下,我们会像这样使用它:

Hash[*arr2]
  #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}

Let's first create arr1 .让我们首先创建arr1 You are right that you need to use Enumerable#each_with_index .你是对的,你需要使用Enumerable#each_with_index You then need to use Enumerable#to_a to convert each element of items to an array [<color>, index] .然后,您需要使用Enumerable#to_aitems每个元素转换为数组[<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]]

Let's look at this more closely:让我们更仔细地看一下:

enum = items.each_with_index 
  #=> #<Enumerator: ["Aqua", "Blue", "Green", "Red", "Yellow"]:each_with_index>

enum , an enumerator, is an instance of the class Enumerator . enum是一个枚举器,是类Enumerator 的一个实例。 The Enumerator class is one of many classes that include s the Enumerable module, of which to_a is an instance method. Enumerator类是include Enumerable模块的众多类之一,其中to_a是一个实例方法。 Not only does:不仅:

arr = enum.to_a
  #=> [["Aqua", 0], ["Blue", 1], ["Green", 2], ["Red", 3], ["Yellow", 4]]

convert the enumerator to the desired array, but it is a convenient way to view the elements of any enumerator (which are generally passed to either a block or to another enumerator).将枚举数转换为所需的数组,但这是查看任何枚举数(通常传递给块或另一个枚举数)的元素的便捷方式。

So we can now create the hash:所以我们现在可以创建哈希:

h = Hash[arr]   
  #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}

or或者

h = Hash[*arr.flatten]
  #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}

or或者

h = arr.to_h
  #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}

Suppose now that we had:现在假设我们有:

items = ["Aqua", "Blue", "Green", "Aqua", "Aqua"]

We then obtain:然后我们得到:

items.each_with_index.to_a.to_h
  #=> {"Aqua"=>4, "Blue"=>1, "Green"=>2}

In building the hash, Ruby first creates the key-value pair "Aqua"=>0 , which she later overwrites with "Aqua"=>3 and then with "Aqua"=>4 .在构建哈希时,Ruby 首先创建键值对"Aqua"=>0 ,然后她用"Aqua"=>3"Aqua"=>4覆盖它。 This is a consequence of the fact that hashes have unique keys.这是散列具有唯一键这一事实的结果。

Build the hash from scratch从头开始构建哈希

Now suppose we start with an empty hash:现在假设我们从一个空的哈希开始:

h = {}

(same as h = Hash.new ) and add key-value pairs: (与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} 

We could alternatively write:我们也可以这样写:

items.size.times { |i| h[items[i]] = i }
  #=> 5
h #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4} 

or或者

(0...items.size).each { |i| h[items[i]] = i }
  #=> 0...5 
h #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4} 

The Ruby way is skip the step h = {} and to use each_with_index , as before, together with Enumerator#with_object : Ruby 方法是跳过步骤h = {}并像以前一样使用each_with_indexEnumerator#with_object

items.each_with_index.with_object({}) { |(s,i),h| h[s] = i }
  #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4} 

The "object" in with_object is a hash, with_object 's argument being its initial value, here an empty hash. with_object的“对象”是一个散列, with_object的参数是它的初始值,这里是一个空散列。 This object is represented by the block variable h and is returned after all elements of items have been enumerated (so we don't need a subsequent line h to return the hash).该对象由块变量h表示,并在枚举items所有元素后返回(因此我们不需要后续行h来返回散列)。

Lets look at the steps that are performed here.让我们看看这里执行的步骤。 First, we have首先,我们有

enum0 = items.each_with_index
  #=> #<Enumerator: ["Aqua", "Blue", "Green", "Red", "Yellow"]:each_with_index> 

which I discussed earlier.我之前讨论过的。 Then Ruby computes然后 Ruby 计算

enum1 = enum0.with_object({})
  #=> #<Enumerator: #<Enumerator: ["Aqua", "Blue", "Green", "Red", "Yellow"]
        :each_with_index>:with_object({})> 

Examine the return value carefully.仔细检查返回值。 As you see, enum1 , like enum0 , is an enumerator.如您所见, enum1enum0一样,是一个枚举器。 You might think of it as a "compound enumerator".您可能会将其视为“复合枚举器”。 To see the values of enum1 that will be passed to the block, you can convert it to an array:要查看将传递给块的enum1的值,您可以将其转换为数组:

enum1.to_a
  #=> [[["Aqua", 0], {}], [["Blue", 1], {}], [["Green", 2], {}],
  #    [["Red", 3], {}], [["Yellow", 4], {}]] 

As you see, enum1 has five elements, each an array containing an array and a hash.如您所见, enum1有五个元素,每个元素都是一个包含一个数组和一个散列的数组。 The elements of enum1 are passed to the block by Enumerator#each , (which calls Array#each ): enum1的元素由Enumerator#each传递给块,(它调用Array#each ):

enum1.each { |(s,i),h| h[s] = i }
  #=> {"Aqua"=>0, "Blue"=>1, "Green"=>2, "Red"=>3, "Yellow"=>4}

We can use Enumerator#next to pass each element of enum1 to the block, and set the block variables to its value.我们可以使用Enumerator#nextenum1每个元素enum1给块,并将块变量设置为其值。 The first is:第一个是:

(s,i),h = enum1.next
  #=> [["Aqua", 0], {}] 
s #=> "Aqua" 
i #=> 0 
h #=> {} 

Notice how [["Aqua", 0], {}] is decomposed into its three constituent elements and each block variable is set equal to one of the elements.请注意[["Aqua", 0], {}]分解为其三个组成元素,并且每个块变量设置为等于其中一个元素。 This is called array decomposition .这称为数组分解

We can now perform the block calculation:我们现在可以执行块计算:

h[s] = i
 #=> {}["Aqua"] = 0

so now:所以现在:

h #=> {"Aqua"=>0}

Then the second element is passed to the block:然后将第二个元素传递给块:

(s,i),h = enum1.next
  #=> [["Blue", 1], {"Aqua"=>0}] 
  s #=> "Blue" 
  i #=> 1 
  h #=> {"Aqua"=>0} 

Notice how h has been updated.注意h是如何更新的。 The block calculation is now:块计算现在是:

h[s] = i
 #=> {"Aqua"=>0}["Blue"] = 1

and now:现在:

h #=> {"Aqua"=>0, "Blue"=>1}

The remaining calculations are performed similarly.其余计算类似。 After all elements of enum1 have been enumerated, enum1.each returns h .之后的所有元素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

You can also try this.你也可以试试这个。

eg例如

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}

Most Rubies大多数红宝石

This works at least as far back as Ruby 1.9.3.这至少可以追溯到 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红宝石 >= 2.1.0

If you're running a recent Ruby, you can simplify the above to:如果您运行的是最新的 Ruby,则可以将上述内容简化为:

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

The results will be the same as above, but the Array#to_h method simplifies the code a lot.结果将与上面相同,但Array#to_h方法大大简化了代码。 However, you still need to flatten the array to avoid results like:但是,您仍然需要展平数组以避免出现以下结果:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM