mbigras
mbigras

Reputation: 8055

Brackets [...] method taking an array as the argument

I read in another answer that the [] method can take an array as an argument.

Both the examples given in the linked post don't illustrate what the actual result is from using this technique.

I tried some examples which also don't provide much information:

[11] pry(main)> a = %w( foo bar baz )
=> ["foo", "bar", "baz"]
[12] pry(main)> a[[1,2]]
TypeError: no implicit conversion of Array into Integer
from (pry):11:in '[]'
[13] pry(main)> a[['foo', 'bar']]
TypeError: no implicit conversion of Array into Integer
from (pry):12:in '[]'
[14] pry(main)> b = { foo: 42, bar: "dolphins", baz: "towels" }
=> {:foo=>42, :bar=>"dolphins", :baz=>"towels"}
[15] pry(main)> b[[:foo, :bar]]
=> nil
[16] pry(main)> b[["dolphins"]]
=> nil

What does it mean for the [] to take an array as an argument? What context is this technique used?

Would appreciate some runnable examples that will help me understand why all my examples return either nil or an error.

Upvotes: 1

Views: 91

Answers (5)

akuhn
akuhn

Reputation: 27793

[] is just another method.

Unlike other languages, Ruby operators are just method and any method can take any object as argument, including an array.

class A
  def [](key)
    p key
  end
  def example(key)
    p key
  end 
end

And then

a = A.new

a[1] # => 1
a[[1, 2, 3]] # => [1, 2, 3]

a.[](1) # => 1
a.[]([1, 2, 3]) # => [1, 2, 3]

a.example(1) # => 1
a.example([1, 2, 3]) # =>  [1, 2, 3]

a.send(:'[]', 1) # => 1
a.send(:'[]', [1, 2, 3]) # => [1, 2, 3]

a.send(:example, 1) # => 1
a.send(:example, [1, 2, 3]) # => [1, 2, 3]

Other operator methods in Ruby are

  • def []=(key, value)
  • def +(other)
  • def -(other)
  • def *(other)
  • def /(other)
  • def %(other)
  • def &(other)
  • def |(other)
  • def ^(other)
  • def ~(other)
  • def ==(other)
  • def ===(other)
  • def <=>(other)
  • def <=(other)
  • def >=(other)
  • def <(other)
  • def >(other)
  • def <<(other)
  • def !
  • def ~
  • def +@ as in +a
  • def -@ as in -a

Upvotes: 1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 120990

This is ruby. Whatever#[] is just a method. Consider Hash class, defining class method Hash#[]. It is used for constructing a Hash instance out of an array of 2-sized arrays:

Hash[[[:foo, 42]]]
#⇒ { :foo => 42 }

Also, Hash itself might have arrays as keys:

hash = { [1, 2, 3] => :foo }
hash[[1, 2, 3]]
#⇒ :foo

Upvotes: 0

Eric Duminil
Eric Duminil

Reputation: 54213

Receiver is a Hash

Receiver could be a Hash, with Arrays as keys

Splat the parameter

You could also splat the array :

a = %w( foo bar baz )
a[*[1,2]]
#=> ["bar", "baz"]

This syntax is equivalent to a[1,2] and means take 2 values beginning at index 1

Define a custom class and [] method

You could also define a custom class and a [] method, accepting any object :

class MyObject
  def self.[](argument)
    "MyObject[] has been called with an #{argument.class}"
    # do something with argument
  end
end

puts MyObject[[1,2,3]]    #=> MyObject[] has been called with an Array
puts MyObject[Object.new] #=> MyObject[] has been called with an Object

Upvotes: 0

mbigras
mbigras

Reputation: 8055

Going off @Jared's answer, the important point is a hash's key can be an array. Another way to say this is a hash's [] method can take an array as an argument.

Also from another perspective: an array's index cannot be an array. Another way to say this is an array's [] method cannot take an array as an argument.

Now the examples above make sense.

[11] pry(main)> a = %w( foo bar baz )
=> ["foo", "bar", "baz"]
[12] pry(main)> a[[1,2]]
TypeError: no implicit conversion of Array into Integer
from (pry):11:in `[]'
[13] pry(main)> a[['foo', 'bar']]
TypeError: no implicit conversion of Array into Integer
from (pry):12:in `[]'

As mentioned above, this is an error because an array takes an integer as an index, not an array.

[14] pry(main)> b = { foo: 42, bar: "dolphins", baz: "towels" }
=> {:foo=>42, :bar=>"dolphins", :baz=>"towels"}
[15] pry(main)> b[[:foo, :bar]]
=> nil
[16] pry(main)> b[["dolphins"]]
=> nil

This isn't an error because a hash's key can be an array. However, the keys [:foo, :bar] and ["dolphins"] haven't been defined so they return nil

Another more illustrative example is:

[1] pry(main)> h = { foo: 42, bar: "cats" }
=> {:foo=>42, :bar=>"cats"}
[2] pry(main)> h[[:foo, :bar]]
=> nil
[3] pry(main)> h[[:foo, :bar]] = "dogs"
=> "dogs"
[4] pry(main)> h[[:foo, :bar]]
=> "dogs"
[5] pry(main)> h
=> {:foo=>42, :bar=>"cats", [:foo, :bar]=>"dogs"}

In [3] we define the key [:foo, :bar] in the hash h to have the value "dogs" so in [4] that's what gets returned, and in [5] we can see the key-value pair inside the hash.

Upvotes: 0

Jared
Jared

Reputation: 1184

If it is a hash you can have the key be an array. So you can look up via that. In your examples you are trying to do something similar on b but it has no matching keys to your array param.

foo = {['bar'] => 'value'}
foo[['bar']]
   => "value"

Upvotes: 0

Related Questions