1

How would I modify (add/remove elements) an array while iterating over it and have the iterator be aware of it?

For example I would think this code:

a = "1234567890".split("")
a.each_with_index{|d, i|
 if d.eql?('5')
  a.delete_at(i)
  a.insert(i, ['A', 'B', 'C'] )
 end
print d
}

would produce: 1234ABC67890 but instead produces 1234567890

Is there a workaround or different method to make this work?

(I know this example is pretty simple example but I am doing some complicated text processing where I need to insert some text when I hit a key word. I do a bunch of functions before and after I would do the expansion so doing the insert outside of the each loop [aka map!] would really complicate my code)

4 Answers 4

1

Actually, your code works, you just need to replace print d with print a[i] since what you're printing is the variable d not the actual array element at index i

Rather than deleting and inserting, why not change the element on that index?

    a = "1234567890".split("")
    a.each_with_index{|d, i|
     if d.eql?('5')
      a[i] = ['A','B','C']
     end
    print a[i] #a[i] rather than d, since d contains the old value
    }

or

 ...
if d.eql?('5')
   a[i] = ['A','B','C']
   d = a[i]
end
print d

Deleting/Inserting on an Array during iterations is discourage since it may cause headaches haha... Resort to other methods if possible :)

Note: I've just used the current logic in your code based on my understanding, and the given desired output

the array will become [1,2,3,4,['A','B','C'],6,7,8,9,0] and not [1,2,3,4,'A','B','C',6,7,8,9,0]. If you want the other, just leave a comment :)

If what you want is just to change a value in the string, you can just use .tr or .gsub to do the job

Sign up to request clarification or add additional context in comments.

4 Comments

you are correct the outcome of code will be [1,2,3,4,['A','B','C'],6,7,8,9,0] but the desired outcome is [1,2,3,4,'A','B','C',6,7,8,9,0]... I guess I need to write an method to expand array into multiple parameters (aka a.insert[i, 'A', 'B', 'C']
the solution is just simple... you can just do an .insert 3 times :) but you have to start backwards. e.g. a.insert(i,'C');a.insert(i,'B');a.insert(i,'A'); since insert will displace the other elements to the left
to the right I mean, If you're gonna view an array growing to the right :)
actually I used the splat operator: a.insert[i, *other_array] not sure why I didn't think of it sooner -thanks
0

Here is one option. If you want to return array then remove join otherwise keep it to return a String

a = "1234567890".split("")
a.collect! {|i| i == '5' ? ['A', 'B', 'C'] : i }.flatten!.join #=> "1234ABC67890"

Comments

0

Inserting and deleting while iterating is best avoided. Some problems disappear however when iterating in reverse order:

a = "1234567890".split("")
a.reverse_each.with_index{|d, i|
 if d.eql?('5')
  a.delete_at(i)
  a.insert(i, ['A', 'B', 'C'] )
 end
}
puts a.join # => 12345ABC7890 

Comments

0

You can't in general modify an Enumerable while iterating over its members. In most such cases, you need to construct a new Enumerable as you go.

b = []
a.each_with_index do |d, i|
  if d.eql?('5')
    b << 'A' << 'B' << 'C'
  else
    b << d
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.