+= vs << when appending arrays to an array

hello,

i’m looking for a nice idiomatic way to append to an array. i’m porting
some encryption code from C to ruby, i don’t have the code in front of
me but a relevant example is below:

def translate(str="")
ret = []
str.each_byte { |byte| ret << byte }
ret
end

bytes = []
bytes << translate(“foo”)
bytes += translate(“foo”)

p bytes

i’m using ruby 1.6.8, btw…

elsewhere in my code, i’m using << to append bytes onto the bytes array,
but for the functions that return arrays of bytes, i have to use += to
make sure the flattened values get added to the target array. if i use
<<, it appends the array returned from the function back onto the target
array. i’d like to use << everywhere as it makes the code more readable
(imo), so is there some syntax i can throw in front of the translate()
call to make the << do the right thing?

i’ve considered both overloading Array.<< or making my own subclass and
making a smarter <<. i realize that << can’t tell if your intent is to
append the array itself ([1,2,3]) or its values (1,2,3). i guess my
real question is, can i get the desired behavior without making a
subclass or redefining <<? i hope my question is clear…

thanks,

doug

···


“Contrary to what most people say, the most dangerous animal in the
world is not the lion or the tiger or even the elephant. It’s a shark
riding on an elephant’s back, just trampling and eating everything they
see.” – Jack Handey

Doug Beaver wrote:

hello,

i’m looking for a nice idiomatic way to append to an array. i’m porting
some encryption code from C to ruby, i don’t have the code in front of
me but a relevant example is below:

def translate(str=“”)
ret =
str.each_byte { |byte| ret << byte }
ret
end

First, use unpack(). It’s faster.

def translate(str=“”)
str.unpack(“C*”)
end

bytes =
bytes << translate(“foo”)
bytes += translate(“foo”)

p bytes

i’m using ruby 1.6.8, btw…

I couldn’t get it to work with << the way that you describe. You have a
couple of options. First, use the splat operator with push(): e.g.

push(*translate(“foo”)).

Another option is to just call bytes.flatten! when you’re done storing
stuff within the bytes array.

I think the only way to get this to work would be to convince Matz that
<<
should accept multiple arguments, the same as push(). Then you could
do:

bytes << *translate(“foo”)

Regards,

Dan

“Doug Beaver” doug@beaver.net schrieb im Newsbeitrag
news:20030715141453.A48963@beaver.net

hello,

i’m looking for a nice idiomatic way to append to an array. i’m porting
some encryption code from C to ruby, i don’t have the code in front of
me but a relevant example is below:

def translate(str=“”)
ret =
str.each_byte { |byte| ret << byte }
ret
end

bytes =
bytes << translate(“foo”)
bytes += translate(“foo”)

p bytes

i’m using ruby 1.6.8, btw…

elsewhere in my code, i’m using << to append bytes onto the bytes array,
but for the functions that return arrays of bytes, i have to use += to
make sure the flattened values get added to the target array. if i use
<<, it appends the array returned from the function back onto the target
array. i’d like to use << everywhere as it makes the code more readable
(imo), so is there some syntax i can throw in front of the translate()
call to make the << do the right thing?

You should use “push” with “*” over “+=” since it is more efficient. “+=”
creates a new instance before reassigning to that:

“+=”:
irb(main):001:0> a=%w{a b c}
[“a”, “b”, “c”]
irb(main):002:0> b=[1,2,3]
[1, 2, 3]
irb(main):003:0> a.id
22401168
irb(main):004:0> a += b
[“a”, “b”, “c”, 1, 2, 3]
irb(main):005:0> a.id
22388400
irb(main):006:0>

“push”:
irb(main):011:0> a=%w{a b c}
[“a”, “b”, “c”]
irb(main):012:0> b=[1,2,3]
[1, 2, 3]
irb(main):013:0> a.id
22192460
irb(main):014:0> a.push *b
[“a”, “b”, “c”, 1, 2, 3]
irb(main):015:0> a.id
22192460
irb(main):016:0>

i’ve considered both overloading Array.<< or making my own subclass and
making a smarter <<. i realize that << can’t tell if your intent is to
append the array itself ([1,2,3]) or its values (1,2,3). i guess my
real question is, can i get the desired behavior without making a
subclass or redefining <<? i hope my question is clear…

You can do it via push, but you can’t with your own implementation of <<
since you would want to do

a << *translate(“foo”)

which isn’t possible to do because it yields a syntax error.

Otherwise you would have to add the logic you mentioned and do a “push *”
for all Enumerables. This way you can never append an array as such with
this operator other than doing:

a << [[1,2,3]]

which is a bit odd because of the nesting.

Regards

robert

I think the only way to get this to work would be to convince Matz that
<<
should accept multiple arguments, the same as push(). Then you could
do:

bytes << *translate(“foo”)

I was just thinking that that was a smart way to do it… I’d expect it
to be there, if I ever had need of that sort of action…

Ari