xyzmg
xyzmg

Reputation: 3

Why doesn't 'each' iterator go through the whole array?

I tried to execute this code in Ruby:

array=[1,2,3,4,5]
array.each do |x|
  puts array.length
  puts "Downloading #{array.length} files"
  array.pop
end

I got:

5
Downloading 5 files
4
Downloading 4 files
3
Downloading 3 files

I don't understand why I'm getting only three iterations. What am I doing wrong (apart from not using a while loop)?

Upvotes: 0

Views: 114

Answers (3)

Abhishek28
Abhishek28

Reputation: 57

In your function, array.pop is decreasing your array's length. In last line

3
Downloading 3 files

your array's length is 3 and your each loop is already run 3 times. that's why its not iterate next element. (Here, each loop iterate only 3 elements because your array's length is 3)

Upvotes: 0

Robin van Dijk
Robin van Dijk

Reputation: 827

What happened before was this:

  1. array.length is 5
  2. x = 1 is being processed
  3. array.shift (array.length is 4)
  4. Array length = 4
  5. x = 2 is being processed
  6. array.shift (array.length is 3)
  7. x = 3 is being processed
  8. array.shift (array.length is 2)

Now there are no more array items to iterate through, because the last 3 items (3,4,5) are popped.

A better way to do is to reverse the array and shift it

array=[1,2,3,4,5]

array.reverse.each do |x|
  puts array.length
  puts "Downloading #{array.length} files"
  array.shift
end

What happens now is, the array now is [5,4,3,2,1]. Each loop it processes the first item in the array, puts the array length, and then removes the value using shift.

Upvotes: 1

Oleksandr Holubenko
Oleksandr Holubenko

Reputation: 4440

It's cause you iterate from begin of array it means:

1 step: puts array[0] and you delete array[4] element(array => [1, 2, 3, 4])
2 step: puts array[1] and delete array[3] element(array => [1, 2, 3])

If you want to delete each element after returned it, you can do it in many variants, some of it:

array.reverse.each do |x|
  puts "Downloading #{x} files"
  array.pop
end

or

array.size.times do
  puts "Downloading #{array.pop} files"
end

If you don't want to get empty array after this iteration, you can just:

array.reverse.each do |x|
  puts "Downloading #{x} files"
end

Upvotes: 0

Related Questions