Array::new

J

Jamie Hodkinson

Just had something unexpected - is this the correct behaviour?

foo = Array.new(3,Array.new)
foo[0] << 4
foo[1] << 5
foo[0] << 6
p foo

outputs...

[[4, 5, 6], [4, 5, 6], [4, 5, 6]]

I realise what's happening here, and might have expected it if the
first line was
foo = Array.new(3,[])

I'm left with doing this:
foo = (1..3).collect { [] }

which doesn't exactly raise my heartbeat. Any other options?

Cheers

Jamie
 
D

Dave Baldwin

Just had something unexpected - is this the correct behaviour?

foo = Array.new(3,Array.new)
foo[0] << 4
foo[1] << 5
foo[0] << 6
p foo

outputs...

[[4, 5, 6], [4, 5, 6], [4, 5, 6]]

I realise what's happening here, and might have expected it if the
first line was
foo = Array.new(3,[])

I'm left with doing this:
foo = (1..3).collect { [] }

which doesn't exactly raise my heartbeat. Any other options?

foo = Array.new(3){Array.new}

gives you what you want.

Dave.
 
J

Jamie Hodkinson

Brilliant, thank you.

Just had something unexpected - is this the correct behaviour?

foo = Array.new(3,Array.new)
foo[0] << 4
foo[1] << 5
foo[0] << 6
p foo

outputs...

[[4, 5, 6], [4, 5, 6], [4, 5, 6]]

I realise what's happening here, and might have expected it if the
first line was
foo = Array.new(3,[])

I'm left with doing this:
foo = (1..3).collect { [] }

which doesn't exactly raise my heartbeat. Any other options?

foo = Array.new(3){Array.new}

gives you what you want.

Dave.
Cheers

Jamie
 
A

Adriano Ferreira

foo = Array.new(3,Array.new)
foo = Array.new(3,[])

I think these are just the same. Indeed, the object creation ([] or
Array.new) happens only once. To have distinct arrays in every slot of
foo you need something like

foo = Array.new(3) { Array.new }
foo[0] << 4
foo[1] << 5
foo[0] << 6
p foo

(as Dave Baldwin suggested) and you'll get

[[4, 6], [5], []]

If you come to this code, by looking at the Array documentation where
the example
Array.new(2, Hash.new) » [{}, {}]
is given, I agree that this documentation is misleading for beginners.

Regards,
Adriano.
 
R

Robert Klemme

Adriano Ferreira said:
foo = Array.new(3,Array.new)
foo = Array.new(3,[])

I think these are just the same.

Nearly: with Array.new you cannot provide a list of values like with [] -
but apart from that: yes, "[]" is syntactical sugar for "Array.new"
followed by some element additions.
Indeed, the object creation ([] or
Array.new) happens only once.

That's the crucial part to understand: "[]" or "Array.new" is an argument
to a method invocation (Array.new) so it's evaluated *once before* the
method is invoked and the second parameter is bound to this value.
Perfectly logical and reasonable.
To have distinct arrays in every slot of
foo you need something like

foo = Array.new(3) { Array.new }
foo[0] << 4
foo[1] << 5
foo[0] << 6
p foo

(as Dave Baldwin suggested) and you'll get

[[4, 6], [5], []]

If you come to this code, by looking at the Array documentation where
the example
Array.new(2, Hash.new) » [{}, {}]
is given, I agree that this documentation is misleading for beginners.

Yep, true. Probably a better example would be
=> [{"foo"=>"bar"}, {"foo"=>"bar"}]

Kind regards

robert
 
G

Gavin Kistner

If you come to this code, by looking at the Array documentation where
the example
Array.new(2, Hash.new) » [{}, {}]
is given, I agree that this documentation is misleading for beginners.

Yep, true. Probably a better example would be
=> [{"foo"=>"bar"}, {"foo"=>"bar"}]

Though even then, it would appear (to someone wanting the specific
functionality of the OP, and probably 'most' cases) that the parameter
is used as a template, with .dup used for each instance. I think the
example should illustrate that the objects are in fact the same, and
discuss the end result each has:

my_array = Array.new( 2, { :foo => :bar } )
my_array[ 1 ][ :jimmy ] = :jammy
p my_array
#=> [{:foo=>:bar, :jimmy=>:jammy}, {:foo=>:bar, :jimmy=>:jammy}]

my_array = Array.new( 2 ){ { :foo => :bar } }
my_array[ 1 ][ :jimmy ] = :jammy
p my_array
#=> [{:foo=>:bar}, {:foo=>:bar, :jimmy=>:jammy}]
 
R

Robert Klemme

Gavin Kistner said:
If you come to this code, by looking at the Array documentation where
the example
Array.new(2, Hash.new) » [{}, {}]
is given, I agree that this documentation is misleading for
beginners.

Yep, true. Probably a better example would be
Array.new(2, {"foo"=>"bar"})
=> [{"foo"=>"bar"}, {"foo"=>"bar"}]

Though even then, it would appear (to someone wanting the specific
functionality of the OP, and probably 'most' cases) that the parameter
is used as a template, with .dup used for each instance.
Probably.

I think the
example should illustrate that the objects are in fact the same, and
discuss the end result each has:

my_array = Array.new( 2, { :foo => :bar } )
my_array[ 1 ][ :jimmy ] = :jammy
p my_array
#=> [{:foo=>:bar, :jimmy=>:jammy}, {:foo=>:bar, :jimmy=>:jammy}]

my_array = Array.new( 2 ){ { :foo => :bar } }
my_array[ 1 ][ :jimmy ] = :jammy
p my_array
#=> [{:foo=>:bar}, {:foo=>:bar, :jimmy=>:jammy}]

Nice, too. Or do
a = Array.new(2, {"foo"=>"bar"}) => [{"foo"=>"bar"}, {"foo"=>"bar"}]
a.map{|o| o.object_id} => [135028744, 135028744]
a.map{|o| o.object_id}.uniq
=> [135028744]

Kind regards

robert
 
D

Dmitriy Genzel

Better yet, I think Array.new in the -w mode should check if it got
called with a second argument that responds to "each" or
perhaps to "[]=" and warn. I can't think of any meaningful use for
Array.new(n, Array.new) or of any use where a container is given
as a default argument of an array in such a manner.

And the same should apply to Hash.new.

Just about any newbie (especially with Perl background) runs into this,
I think. I know I did.

Dmitriy

Gavin Kistner said:
If you come to this code, by looking at the Array documentation
where
the example
Array.new(2, Hash.new) » [{}, {}]
is given, I agree that this documentation is misleading for beginners.

Yep, true. Probably a better example would be

Array.new(2, {"foo"=>"bar"})
=> [{"foo"=>"bar"}, {"foo"=>"bar"}]

Though even then, it would appear (to someone wanting the specific
functionality of the OP, and probably 'most' cases) that the parameter
is used as a template, with .dup used for each instance.
Probably.

I think the
example should illustrate that the objects are in fact the same, and
discuss the end result each has:

my_array = Array.new( 2, { :foo => :bar } )
my_array[ 1 ][ :jimmy ] = :jammy
p my_array
#=> [{:foo=>:bar, :jimmy=>:jammy}, {:foo=>:bar, :jimmy=>:jammy}]

my_array = Array.new( 2 ){ { :foo => :bar } }
my_array[ 1 ][ :jimmy ] = :jammy
p my_array
#=> [{:foo=>:bar}, {:foo=>:bar, :jimmy=>:jammy}]

Nice, too. Or do
a = Array.new(2, {"foo"=>"bar"}) => [{"foo"=>"bar"}, {"foo"=>"bar"}]
a.map{|o| o.object_id} => [135028744, 135028744]
a.map{|o| o.object_id}.uniq
=> [135028744]

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,171
Messages
2,570,935
Members
47,472
Latest member
KarissaBor

Latest Threads

Top