27

How can I substitue an element in an array?

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

I need to replace 5 with [11,22,33,44].flatten!

so that a now becomes

a = [1,2,3,4,11,22,33,44]
Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
gweg
  • 2,820
  • 6
  • 23
  • 23
  • 1
    please give us an explanation as to why you are needing to do this and in what context this is – Earlz Nov 10 '09 at 00:06
  • might want to change the title to how do I substitute array elements in a ruby 'each' style iterator – peterk Aug 01 '14 at 12:52

8 Answers8

45

Not sure if you're looking to substitute a particular value or not, but this works:

a = [1, 2, 3, 4, 5]
b = [11, 22, 33, 44]
a.map! { |x| x == 5 ? b : x }.flatten!

This iterates over the values of a, and when it finds a value of 5, it replaces that value with array b, then flattens the arrays into one array.

Ryan McGeary
  • 235,892
  • 13
  • 95
  • 104
  • 2
    While this does work, it's overly complicated for what the original poster is trying to do. Using array-slicing to replace a range is a more straight-forward and simple solution. See [this answer](http://stackoverflow.com/a/1704805/456814). –  Mar 27 '14 at 08:08
  • @Ryan McGeary I need a same method except the value of 5 I want to replace all numbers in the array divisible by 3 with a word "BINGO". How to do that. I tried `ary = (0..100).to_a ary.map!{|i| i % 3 == 0 ? i : "BINGO" }` It replaces all except those divisible by 3 – DebRaj Feb 13 '16 at 12:46
19

Perhaps you mean:

a[4] = [11,22,33,44] # or a[-1] = ...
a.flatten!

A functional solution might be nicer, how about just:

a[0..-2] + [11, 22, 33, 44]

which yields...

=> [1, 2, 3, 4, 11, 22, 33, 44]
DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • 1
    +1 Thanks! The functional solution was more adaptable to when I wanted to replace a single element by two values at a variable location in the array, i.e.: a[0..b-1] + [val1, val2] + [b+1..-1] – mm2001 Jan 29 '14 at 05:42
14

The version of bta using a.index(5) is the fastest one:

a[a.index(5)] = b if a.index(5) # 5.133327 sec/10^6

At least 10% faster than Ryan McGeary's one:

a.map!{ |x| x == 5 ? b : x } # 5.647182 sec/10^6

However, note that a.index(5) only return the first index where 5 is found. So, given an array where 5 appears more than once, results will be different:

a = [1, 2, 3, 4, 5, 5]
b = [11,22,33,44]

a[a.index(5)] = b if a.index(5)
a.flatten # => [1, 2, 3, 4, 11, 22, 33, 44, 5]

a.map!{ |x| x == 5 ? b : x }
a.flatten # => [1, 2, 3, 4, 11, 22, 33, 44, 11, 22, 33, 44]
Community
  • 1
  • 1
Guillaume
  • 705
  • 6
  • 7
7

Array#delete will return the item or nil. You may use this to know whether or not to push your new values

a.push 11,22,33,44 if a.delete 5
chrissrogers
  • 226
  • 2
  • 2
5

You really don't have to flatten if you just concatenate. So trim the last element off the first array and concatenate them:

a = [ 1, 2, 3, 4, 5 ]           #=> [1, 2, 3, 4, 5]
t = [11, 22, 33, 44]            #=> [11, 22, 33, 44]
result = a[0..-2] + t           #=> [1, 2, 3, 4, 11, 22, 33, 44]

a[0..-2] is a slice operation that takes all but the last element of the array.

Hope it helps!

Benjamin Cox
  • 6,090
  • 21
  • 19
5

This variant will find the 5 no matter where in the array it is.

a = [1, 2, 3, 4, 5]
a[a.index(5)]=[11, 22, 33, 44] if a.index(5)
a.flatten!
bta
  • 43,959
  • 6
  • 69
  • 99
2

Here is another simple way to replace the value 5 in the array:

a[-1, 1] = [11, 22, 33, 44]

This uses the Array#[]= method. I'm not exactly sure why it works though.

0

gweg, not sure what you're trying to do here, but are you looking for something like this?

a = [1, 2, 3, 4, 5]
a.delete_at(4)
a = a.concat([11,22,33,44])

There are a number of ways of doing this -- I don't think the code above is especially nice looking. It all depends on the significance of '5' in your original array.

Mike Seplowitz
  • 9,785
  • 1
  • 24
  • 23