简体   繁体   中英

issue with using inject to convert array to hash

data_arr = [['dog', 'Fido'], ['cat', 'Whiskers'], ['fish', 'Fluffy']]

data_hash = data_arr.inject({}) do |hsh, v|
    hsh[v[0]] = v[1]
    hsh
end

Hi, why do I not need to initialize data_hash as an empty hash? And why do I have to add hsh in the last line if not it will result in an error.

why do I not need to initialize data_hash as an empty hash?

You do, implicitly. The value passed to inject , ie {} will become the initial value for hsh which will eventually become the value for data_hash . According to the documentation :

At the end of the iteration, the final value of memo is the return value for the method.

Let's see what happens if we don't pass {} :

If you do not explicitly specify an initial value for memo , then the first element of collection is used as the initial value of memo .

The first element of your collection is the array ['dog', 'Fido'] . If you omit {} , then inject would use that array as the initial value for hsh . The subsequent call to hsh[v[0]] = v[1] would fail, because of:

hsh = ['dog', 'Fido']
hsh['cat'] = 'Whiskers'
#=> TypeError: no implicit conversion of String into Integer

why do I have to add hsh in the last line

Again, let's check the documentation:

[...] the result [of the specified block] becomes the new value for memo .

inject expects you to return the new value for hsh at the end of the block.

if not it will result in an error.

That's because an assignment like hsh[v[0]] = v[1] returns the assigned value, eg 'Fido' . So if you omit the last line, 'Fido' becomes the new value for hsh :

hsh = 'Fido'
hsh['cat'] = 'Whiskers'
#=> IndexError: string not matched

There's also each_with_object which works similar to inject , but assumes that you want to mutate the same object within the block. It therefore doesn't require you to return it at the end of the block: (note that the argument order is reversed)

data_hash = data_arr.each_with_object({}) do |v, hsh|
  hsh[v[0]] = v[1]
end
#=> {"dog"=>"Fido", "cat"=>"Whiskers", "fish"=>"Fluffy"}

or using array decomposition :

data_hash = data_arr.each_with_object({}) do |(k, v), hsh|
  hsh[k] = v
end
#=> {"dog"=>"Fido", "cat"=>"Whiskers", "fish"=>"Fluffy"}

Although to convert your array to a hash you can simply use Array#to_h , which is

[...] interpreting ary as an array of [key, value] pairs

data_arr.to_h
#=> {"dog"=>"Fido", "cat"=>"Whiskers", "fish"=>"Fluffy"}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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