0

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)?

sawa
  • 165,429
  • 45
  • 277
  • 381
xyzmg
  • 3
  • 1
  • 4
    Do not mutate enumerables while iterating. This question was a dozillion times answered here. – Aleksei Matiushkin Mar 02 '17 at 10:21
  • Relevant question: [Change value of array element which is being referenced in a .each loop?](http://stackoverflow.com/q/5646710/2620080) – ScieCode Mar 02 '17 at 10:27
  • If you provide an explanation about what you want, we might be able to provide you a different solution. – ScieCode Mar 02 '17 at 10:29
  • 1
    I'm a complete beginner. I know I can do this iteration differently, but I didn't understand why I was getting only iterations till array consisted of 3 elements. Thank you for your hints. – xyzmg Mar 02 '17 at 10:31

3 Answers3

1

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.

Robin van Dijk
  • 827
  • 7
  • 18
0

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
Oleksandr Holubenko
  • 4,310
  • 2
  • 14
  • 28
0

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)

Abhishek28
  • 57
  • 6