# Array#collect in a method call, not working for me

**URL:** <https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878>\
**Category:** Ruby\
**Created:** [October 26, 2009, 5:19am UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878 "2009-10-26T05:19:03Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 26, 2009, 5:19am UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/1 "2009-10-26T05:19:03Z")

</div>

I am sure I’m making a newbie mistake, as I’ve just started learning  
Ruby, and would really appreciate someone pointing out what I’ve done  
wrong, why it is wrong, and how it _should_ be done. Thanks in advance.

I am writing a method definition to double any number, or all numbers if  
an array of numbers is passed to it. When I use array.collect outside of  
the method, it works as expected. When I place it inside of the method,  
instead of multiplying each integer, it treats the entire array as one  
object and double it, [1, 2, 3, 4] becoming 12341234.

I’ve attached my test code, “simplea.rb”, and below is the output when I  
run it. In case it matters to anyone, I’m running Ruby 1.8.7 under  
Cygwin (because I hate windows and don’t have a Mac yet). 😉

$ simplea.rb

Test double([1, 2, 3, 4])

12341234

Test double( 3 )

6

Let’s prove it.  
2  
4  
6  
8

---

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 26, 2009, 7:32am UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/2 "2009-10-26T07:32:38Z")

</div>

On Mon, Oct 26, 2009 at 1:19 PM, Michael R. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> I am writing a method definition to double any number, or all numbers if  
> an array of numbers is passed to it. When I use array.collect outside of  
> the method, it works as expected. When I place it inside of the method,  
> instead of multiplying each integer, it treats the entire array as one  
> object and double it, [1, 2, 3, 4] becoming 12341234.

Using code similar to yours…  
You could try this or something like this.

def double(n)  
[n].flatten.map {|num| num \* 2 }  
end

puts double([1, 2, 3, 4])  
puts  
puts double(3)

Harry

---

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 26, 2009, 1:31pm UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/3 "2009-10-26T13:31:30Z")

</div>

2009/10/26 Michael R. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> I’ve attached my test code, “simplea.rb”, and below is the output when I  
> Test double( 3 )
> 
> Attachments:  
> [http://www.ruby-forum.com/attachment/4184/simplea.rb](http://www.ruby-forum.com/attachment/4184/simplea.rb)

There are a few issues with the first line:

my\_a = [n].to\_a unless n.class == “Array”

First, the test will always fail because the class and the name of the  
class are of different types:

irb(main):002:0\> Array == “Array”  
=\> false

Then, you only need either “[n]” or “n.to\_a” but not both. I  
recommend the former (the latter is deprecated).

Here is _one_ way to do it:

def double(x)  
Enumerable === x ? x.map {|i| i \* 2} : x \* 2  
end

irb(main):006:0\> double 1  
=\> 2  
irb(main):007:0\> double [1,2,3]  
=\> [2, 4, 6]

(Note, #map is the same as #collect.)

— spoiler warning —

An alternative is to use the splat operator and always work with Arrays:

def double(\*a)  
a.map {|i| i \* 2}  
end

irb(main):011:0\> double 1  
=\> [2]  
irb(main):012:0\> double 1,2,3  
=\> [2, 4, 6]  
irb(main):013:0\> double [1,2,3]  
=\> [[1, 2, 3, 1, 2, 3]]

Or, a bit more sophisticated

def double(\*a)  
a.flatten.map {|i| i \* 2}  
end

irb(main):017:0\> double 1  
=\> [2]  
irb(main):018:0\> double 1,2,3  
=\> [2, 4, 6]  
irb(main):019:0\> double [1,2,3]  
=\> [2, 4, 6]

And finally with special treatment of case 1 element:

def double(\*a)  
a.flatten!

case a.size  
when 0  
raise ArgumentError, “need values”  
when 1  
a.first \* 2  
else  
a.map {|i| i \* 2}  
end  
end

irb(main):054:0\> double 1  
=\> 2  
irb(main):055:0\> double 1,2,3  
=\> [2, 4, 6]  
irb(main):056:0\> double [1,2,3]  
=\> [2, 4, 6]

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 26, 2009, 8:44pm UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/4 "2009-10-26T20:44:52Z")

</div>

OK, I _thought_ that part was working, but now I see that it wasn’t  
really. So to help me understand I wrote the following, to see what it  
does and I see that adding the #inspect will give me the string to  
compare against.

But does that mean that (a = [1, 2].class) is setting a to be an Array?  
Oh, and thank you!

Here is my test…

irb(main):034:0\* def proovy( n )  
irb(main):035:1\> a = n.class.inspect  
irb(main):036:1\> b = n.class  
irb(main):037:1\> puts “a: #{a}”  
irb(main):038:1\> puts “b: #{b}”  
irb(main):039:1\> case a  
irb(main):040:2\> when “Array” : puts “a matched Array in case”  
irb(main):041:2\> when “Fixnum” : puts “a matched Fixnum in case”  
irb(main):042:2\> end  
irb(main):043:1\> case b  
irb(main):044:2\> when “Array” : puts “b matched Array in case”  
irb(main):045:2\> when “Fixnum” : puts “b matched Fixnum in case”  
irb(main):046:2\> end  
irb(main):047:1\> end  
=\> nil  
irb(main):048:0\> proovy(1)  
a: Fixnum  
b: Fixnum  
a matched Fixnum in case  
=\> nil  
irb(main):049:0\> proovy([1, 2, 3])  
a: Array  
b: Array  
a matched Array in case  
=\> nil

Robert K. wrote:

> 2009/10/26 Michael R. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
> 
> > I’ve attached my test code, “simplea.rb”, and below is the output when I  
> > Test double( 3 )
> > 
> > Attachments:  
> > [http://www.ruby-forum.com/attachment/4184/simplea.rb](http://www.ruby-forum.com/attachment/4184/simplea.rb)
> 
> There are a few issues with the first line:
> 
> my\_a = [n].to\_a unless n.class == “Array”
> 
> First, the test will always fail because the class and the name of the  
> class are of different types:
> 
> irb(main):002:0\> Array == “Array”  
> =\> false

[…]

> robert

---

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 26, 2009, 9:03pm UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/5 "2009-10-26T21:03:43Z")

</div>

> But does that mean that (a = [1, 2].class) is setting a to be an Array?

Consider this:

> > n = []  
> > =\> []
> 
> > a = n.class  
> > =\> Array
> 
> > a \<\< 1  
> > NoMethodError: undefined method `\<\<’ for Array:Class

a doesn’t become an array, it becomes the class type of Array.

Regards,

- Mac

---

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 26, 2009, 9:11pm UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/6 "2009-10-26T21:11:44Z")

</div>

Michael L. wrote:

> > But does that mean that (a = [1, 2].class) is setting a to be an Array?  
> > Consider this:
> > 
> > > n = []  
> > > =\> []
> > 
> > > a = n.class  
> > > =\> Array
> > 
> > > a \<\< 1  
> > > NoMethodError: undefined method `\<\<’ for Array:Class
> 
> a doesn’t become an array, it becomes the class type of Array.  
> Regards,
> 
> - Mac

That makes sense. And I don’t know why I didn’t think to do the  
following to test it myself…

irb(main):061:0\> n = []  
=\> []  
irb(main):062:0\> a = n.class  
=\> Array  
irb(main):063:0\> a.class  
=\> Class

THANKS!!

---

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 27, 2009, 9:39am UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/7 "2009-10-27T09:39:16Z")

</div>

Please do not top post.

2009/10/26 Michael R. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> irb(main):034:0\* def proovy( n )  
> irb(main):045:2\> when “Fixnum” : puts “b matched Fixnum in case”  
> irb(main):046:2\> end  
> irb(main):047:1\> end

Note that you can simplify the test:

irb(main):004:0\> [[], “foo”].each {|obj| case obj  
irb(main):005:2\> when Array  
irb(main):006:2\> printf “%p is an array\n”, obj  
irb(main):007:2\> when String  
irb(main):008:2\> printf “%p is a string\n”, obj  
irb(main):009:2\> else  
irb(main):010:2\* printf “i don’t know what %p is.\n”, obj  
irb(main):011:2\> end}  
[] is an array  
“foo” is a string  
=\> [[], “foo”]

case uses the === operator:

irb(main):012:0\> Array === [1,2,3]  
=\> true  
irb(main):013:0\> Array === “foo”  
=\> false  
irb(main):014:0\> String === “foo”  
=\> true

IMHO testing against the class is superior to testing against the  
type’s name. Here’s why: in case of inheritance the name test will  
fail while the class test still succeeds

irb(main):016:0\> class FooArray \< Array; end  
=\> nil  
irb(main):017:0\> Array === FooArray.new  
=\> true  
irb(main):018:0\> “Array” === FooArray.name  
=\> false

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 27, 2009, 10:44am UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/8 "2009-10-27T10:44:45Z")

</div>

> my\_a = [n].to\_a unless n.class == “Array”

I think what you were trying to write is:

my\_a = n  
my\_a = [n] unless n.class == Array

There is actually a Ruby idiom for this:

my\_a = Array(n)

Type ‘ri Kernel#Array’ for more info.

This is a normal method which just happens to start with a capital  
letter, which can be confusing. The Ruby interpreter doesn’t confuse  
this with a constant (or class name) because it is followed by  
parentheses, so it must be a method call.

Another version of your original code would be:

my\_a = n.is\_a?(Array) ? n : [n]

However such class tests are very rare in idiomatic Ruby. Duck-typing  
means you don’t care what class an object is, just what methods it  
responds to.

Since the only method you are going to call is ‘collect’, you could  
write:

my\_a = n.respond\_to?(:collect) ? n : [n]

Then the caller could pass in _any_ object which has a ‘collect’ method,  
and you would use that. Only if it doesn’t would it get wrapped in an  
Array.

The benefit here is that you could pass in an Enumerable object (such as  
an open file), and you could process its elements as they are read  
without having to turn the whole file into an Array first.

But equally reasonable would be to drop the [n] part altogether, and  
simply define the method as taking an Enumerable object. It would then  
be the caller’s responsibility to wrap the object if required.

def double( n )  
n.collect {|num| num \* 2 }  
end

puts “\nTest double([1, 2, 3, 4])”  
inttest = double( [1, 2, 3, 4] )  
puts “\n#{inttest}\n\n”

puts “\nTest double( [3] )”  
inttest = double( [3] )  
puts “\n#{inttest}\n\n”

This is what tends to happen in idiomatic ruby - the number of lines of  
code becomes extremely small 🙂

HTH,

Brian.

---

<div class="post-metadata">

**Author:** ![roa](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e7dd6/32.png) [@roa](https://www.ruby-forum.com/u/roa)\
**Post date:** [October 28, 2009, 12:18am UTC](https://www.ruby-forum.com/t/array-collect-in-a-method-call-not-working-for-me/177878/9 "2009-10-28T00:18:21Z")

</div>

Brian C. wrote a bunch of helpful and educational stuff:  
[…]

> HTH,
> 
> Brian.

More than helpful Brian. Quite educational, and I applaud you.

Michael
