+= 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