93

I'm just learning Ruby so apologies if this is too newbie for around here, but I can't work this out from the pickaxe book (probably just not reading carefully enough). Anyway, if I have an array like so:

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

...and I want to, say, multiply each value in the array by 3, I have worked out that doing the following:

arr.each {|item| item *= 3}

...will not get me what I want (and I understand why, I'm not modifying the array itself).

What I don't get is how to modify the original array from inside the code block after the iterator. I'm sure this is very easy.

Chris Barlow
  • 3,274
  • 4
  • 31
  • 52
brad
  • 9,573
  • 12
  • 62
  • 89

4 Answers4

153

Use map to create a new array from the old one:

arr2 = arr.map {|item| item * 3}

Use map! to modify the array in place:

arr.map! {|item| item * 3}

See it working online: ideone

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
21

To directly modify the array, use arr.map! {|item| item*3}. To create a new array based on the original (which is often preferable), use arr.map {|item| item*3}. In fact, I always think twice before using each, because usually there's a higher-order function like map, select or inject that does what I want.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • What if you don't want to do an enumerating operation? What if you just want to do something like `arr.map!{ destructive_op}` to permanently change `arr`? – bright-star Nov 27 '13 at 06:27
  • 1
    @TrevorAlexander: I'm not sure what you mean. It might be worth asking as a real question with details and stuff. – Chuck Nov 27 '13 at 19:07
  • I'll have to think about it. Other than very narrow element modification, what destructive operations on structures aren't enumerable? – bright-star Nov 27 '13 at 21:56
  • @TrevorAlexander: I am still having a hard time understanding. If you can't look at a structure's contents, you can't transform its contents. It kind of sounds like you aren't interested in modifying a structure, and instead just want to assign a variable — but I might be misunderstanding. – Chuck Nov 27 '13 at 22:02
5
arr.collect! {|item| item * 3}
Botz3000
  • 39,020
  • 8
  • 103
  • 127
0

Others have already mentioned that array.map is the more elegant solution here, but you can simply add a "!" to the end of array.each and you can still modify the array. Adding "!" to the end of #map, #each, #collect, etc. will modify the existing array.

  • Tried this, but for both `each!` and `each_with_index!` I get an undefined method error – Ryan Pierce Williams Dec 05 '22 at 19:43
  • This is wrong, as there's no built-in method in Ruby's like each! and/or each_with_index!. I'd recommend to double check your answer, Andrew. This applies to some methods only (map!, compact!, collect!, reject!, etc). – Sebastián Palma Aug 01 '23 at 14:18