Question: arrays v. ranges and *.each

The results of the following code just seem strange to me:

  print "\nTry 1:"
  print [1..10].class, "\n"
  [1..10].each { |x| print x, "\n" }

  print "\nTry 2:"
  print [1..10].pop.class, "\n"
  [1..10].pop.each { |x| print x, "\n" }

I would have thought that either 1) try 1 would output a sequence of
numbers, and try 2 would result in an error (no such method
Integer#each); or, 2) try 1 would output a series of numbers and try 2
would result in an error (no such method Range#pop). Perhaps - another
option would be 3) try 1 would result in '1..10' and try 2 would result
in something like '1..1' or an error?

I'm confused...

the .. operator does not output a series of numbers, but rather an
instance of the class Range.

Try 1 is an array with a single element, a Range object. Calling each
on the array yields each element, in this case the single Range
object, and you've output it to the console, which gives "1..10" which
is how the Range responds to to_s.

Try 2 is the same array. You pop the first element, which is the
Range object, and call each, which iterates over the numbers
represented by the range.

Try this:
(1..10).entries

That gives you an array of all the elements represented by the Range.

Jason

···

On 7/12/05, David Douthitt <ssrat@mailbag.com> wrote:

The results of the following code just seem strange to me:

  print "\nTry 1:"
  print [1..10].class, "\n"
  [1..10].each { |x| print x, "\n" }

  print "\nTry 2:"
  print [1..10].pop.class, "\n"
  [1..10].pop.each { |x| print x, "\n" }

I would have thought that either 1) try 1 would output a sequence of
numbers, and try 2 would result in an error (no such method
Integer#each); or, 2) try 1 would output a series of numbers and try 2
would result in an error (no such method Range#pop). Perhaps - another
option would be 3) try 1 would result in '1..10' and try 2 would result
in something like '1..1' or an error?

I'm confused...

Hi David,

The results of the following code just seem strange to me:

  print "\nTry 1:"
  print [1..10].class, "\n"
  [1..10].each { |x| print x, "\n" }

You are mixing two things here: a range and an array.
[1..10] is an array of one object (1..10) which is an
instance of the Range class.

  print "\nTry 2:"
  print [1..10].pop.class, "\n"
  [1..10].pop.each { |x| print x, "\n" }

so [1..10].pop gives (1..10).

And Range itself is Enumerable.

so: (1..10).each {|i| p i} is a valid construct.

I would have thought that either 1) try 1 would output a sequence of
numbers, and try 2 would result in an error (no such method
Integer#each); or, 2) try 1 would output a series of numbers and try 2
would result in an error (no such method Range#pop). Perhaps - another
option would be 3) try 1 would result in '1..10' and try 2 would result
in something like '1..1' or an error?

I'm confused...

HTH,
-- shanko

···

--- David Douthitt <ssrat@mailbag.com> wrote:

____________________________________________________
Sell on Yahoo! Auctions – no fees. Bid on great items.

The results of the following code just seem strange to me:

  print "\nTry 1:"
  print [1..10].class, "\n"

[ ... ] builds an Array. 1..10 builds a Range. So Ruby sees this as an Array with a single member, a Range.

As an aside, you should look into puts():

puts [1..10].class # no newline needed!

  [1..10].each { |x| print x, "\n" }

So here we are printing the one member, the Range.

  print "\nTry 2:"
  print [1..10].pop.class, "\n"

Here we remove the Array's one member (again a Range) and show its class.

  [1..10].pop.each { |x| print x, "\n" }

Again, printing the one popped member.

Now all of that discusses what you showed, not what you meant. Let's talk about that.

It seems to me you are trying to treat a Range as an Array. The first thing to know there is that Ranges are already Enumerable:

irb(main):006:0> (1..10).each { |n| puts n }
1
2
3
4
5
6
7
8
9
10
=> 1..10

The other fact that may be of use to you is that we can turn a Range into an Array, as needed:

irb(main):007:0> ("a".."j").to_a
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]

Hope that clears some things up.

James Edward Gray II

···

On Jul 12, 2005, at 11:50 AM, David Douthitt wrote:

"David Douthitt" <ssrat@mailbag.com> writes:

The results of the following code just seem strange to me:

  print "\nTry 1:"
  print [1..10].class, "\n"
  [1..10].each { |x| print x, "\n" }

  print "\nTry 2:"
  print [1..10].pop.class, "\n"
  [1..10].pop.each { |x| print x, "\n" }

I would have thought that either 1) try 1 would output a sequence of
numbers, and try 2 would result in an error (no such method
Integer#each); or, 2) try 1 would output a series of numbers and try 2
would result in an error (no such method Range#pop). Perhaps - another
option would be 3) try 1 would result in '1..10' and try 2 would result
in something like '1..1' or an error?

I'm confused...

Well, `a..b' is a range and `[foo]' is an array of one element, so
rather naturally `[a..b]' is an array containing one element: a range.

You can get an array from a range by doing `(a..b).to_a'.

   print "\nTry 2:"
   print (1..10).to_a.pop.class, "\n"
   (1..10).to_a.pop.each { |x| print x, "\n" }

Of course, ranges are already enumerable, so this works OK:

   print "\nTry 1:"
   print (1..10).class, "\n"
   (1..10).each { |x| print x, "\n" }

···

--
Daniel Brockman <daniel@brockman.se>

    So really, we all have to ask ourselves:
    Am I waiting for RMS to do this? --TTN.

Shashank Date wrote:

You are mixing two things here: a range and an array.
[1..10] is an array of one object (1..10) which is an
instance of the Range class.

Aha! That explains it all... So then:

  puts ([1..10] == 1..10 ? "true" : "false")

returns "false" - a complicated way to say 1..10 and [1..10] are not
the same thing :slight_smile:

So, in my original programming, what I wanted was not "[1..10]" but
"(1..10)". It all makes sense now.

Thanks all!

puts [1..10] == (1..10)

:wink:

James Edward Gray II

···

On Jul 12, 2005, at 12:20 PM, David Douthitt wrote:

  puts ([1..10] == 1..10 ? "true" : "false")

Don't feel bad... this tripped me up as well too.

···

On 7/12/05, David Douthitt <ssrat@mailbag.com> wrote:

Shashank Date wrote:

> You are mixing two things here: a range and an array.
> [1..10] is an array of one object (1..10) which is an
> instance of the Range class.

Aha! That explains it all... So then:

  puts ([1..10] == 1..10 ? "true" : "false")

returns "false" - a complicated way to say 1..10 and [1..10] are not
the same thing :slight_smile:

So, in my original programming, what I wanted was not "[1..10]" but
"(1..10)". It all makes sense now.