Replacing an Element in Nested Array Ruby

replacing an element in nested array ruby

class BingoBoard

def initialize(board)
@bingo_board = board
end

def number_letter

@letter = ['B','I','N','G','O'].sample
@number = rand(1..100)

end

def checker
number_letter
@bingo_board.each do |n|
index = n.index(@number)
n[index] = 'X' unless index.nil?
end

end

end

How to replace element in multidimensional array in ruby

This is the root of the problem:

@bingo_board.collect! { |i| (i == @ball) ? "X" : i}

In this example, i is an array. So what you might want to do is to replace your code with something like:

@bingo_board.collect! do |i| # you're iterating over a double array here
if i.include?(@ball) # i is a single array, so we're checking if the ball number is included
i[i.index(@ball)] = 'X'; i # find the index of the included element, replace with X
else
i
end
end

Or if you prefer one-liner:

@bingo_board.collect! { |i| i.include?(@ball) ? (i[i.index(@ball)] = 'X'; i) : i }

Be aware that this is going to only replace the first occurrence of the element. So, say if your ball is 10, and you have:

[8, 9, 9, 10, 10]

you will get:

[8, 9, 9, "X", 10]

If you want ALL of the 10s to be replaced, then do something like:

@bingo_board.collect! do |i|
if i.include?(@ball)
i.collect! { |x| x == @ball ? 'X' : x }
else
i
end
end

Ruby: replacing a matching element in a multidimensional array?

Let me know if this works out (tried to reduce the variations from 1 to 10 in order to be able to test easier):

class Lotto

def initialize
@lotto_slip = Array.new(5) {Array(6.times.map{rand(1..10)})}
end

def current_pick
@number = rand(1..10)
puts "The number is #{@number}."
end

def has_number
#prints out initial slip
@lotto_slip.each {|x| p x}

#Prints slip with an "X" replacing number if is on slip
#Ex: @number equals 4th number on slip --> 1, 2, 3, X, 5, 6
@lotto_slip.each do |z|
if z.include?(@number)
p "#{@number} included in #{z}"
z.map! { |x| x == @number ? 'X' : x}
end
end
@lotto_slip
end
end

test = Lotto.new
test.current_pick
p test.has_number

The problems I saw with your code are:

  • You don't need the to_s for this line @number = rand(1..60).to_s, else how are you going to compare the numbers produced by the array with an actual string?

  • You need to re-generate the array instead of re-assigning, that's why I've replaced all of that code with z.map! { |x| x == @number ? 'X' : x} which basically re-generates the entire array.

Find and replace in a Ruby multi dimensional array

Following sepp2k idea, here is a possible implementation:

class Object
def deep_map(&block)
if self.respond_to? :each
result = []
self.each do |e|
result << e.deep_map(&block)
end
return result
else
return block.call(self)
end
end
end

Then apply deep_map as you wish on the array:

> [[[3, 3, 5], [4, 3, 3]], [[3, 2, 3], [0, 3, 8]]].deep_map { |e| e > 3 ? 0 : e }
=> [[[3, 3, 0], [0, 3, 3]], [[3, 2, 3], [0, 3, 0]]]

Or, more briefly:

class Object
def deep_map(&block)
respond_to?(:map) ? map{|e| e.deep_map(&block)} : block.call(self)
end
end

Or, polymorphically:

class Object
def deep_map(&block); block.call(self) end
end

class Array
def deep_map(&block); map{|e| e.deep_map(&block)} end
end

How to convert a part of nested arrays

Looping over an array with each does not change it. Even if you override the loop variable (rec_upd_date) it does not change the actual value.

In order to mutate an array you should use map:

csv = csv.map do |rec_upd_date|
"#{rec_upd_date.slice(8,2)}/#{rec_upd_date.slice(5,2)}/#{rec_upd_date.slice(0,4)}"
end

The return value of each iteration will be the value of the respective item in the resulting array.

or, you can shorten this with the change in-place version of map!:

csv.map! do |rec_upd_date|
"#{rec_upd_date.slice(8,2)}/#{rec_upd_date.slice(5,2)}/#{rec_upd_date.slice(0,4)}"
end

For example:

csv = ["2015-03-20 10:17:20 +0200", "2015-04-14 10:17:20 +0200", "2013-12-24 10:17:20 +0200"]
csv = csv.map do |rec_upd_date|
"#{rec_upd_date.slice(8,2)}/#{rec_upd_date.slice(5,2)}/#{rec_upd_date.slice(0,4)}"
end
# => ["20/03/2015", "14/04/2015", "24/12/2013"]

For an input like:

[["03/20/2015", A, B],["06/03/2015", C, D],
["04/22/2015", E, F],["03/20/2015", A2, B2],
["06/03/2015", C2, D2],["01/03/2015", E2, F2],
["12/20/2015", A3, B3],["11/05/2015", C3, D3],
["07/15/2015", E3, F3]]

and you want to change only the first element of each item:

[["20/03/2015", A, B],["03/06/2015", C, D],
["22/04/2015", E, F], ...]

the simplest solution will be to return an array for each iteration:

csv.map do |arr|
[do_something_to(arr[0]), arr[1], arr[2]]
end

Another option is, to set the first element of each array item. Since you are not trying to replace the item, but only to modify it, using each will work:

csv.each do |arr|
arr[0] = do_something_to(arr[0])
end

Setting the value of an element within a nested array

I figured it out. When I initialized @board with Array.new(10, Array.new(10)), it created an Array of 10 identical Arrays. That is, each Array had the same object_id.

@board[0].object_id
=> 22148328
@board[1].object_id
=> 22148328

I solved the issue by using the map method:

@board = Array.new(10).map{ |x| Array.new(10) }

replace values of an array within range

You can use Array#fill method.

array.fill(7, 8..100)

Ruby dynamically updating value in nested array

Your iteration is almost there, you just need to stop one step before you run through path so that you can have the array you need to modify rather than the element.

So split the path into the pieces you want:

*p, target = path
# [3], 1

Then use #inject to find the array:

ary = p.inject(example) { |i, a| a[i] }
# [3, 4]

and then do your assignment:

ary[target] = 9

Of course you'll need to add some logic to deal with the unexpected such as path leading you to a non-array element or path not matching the structure of example (consider path = [11, 6, 23] in your example).

You could also use #dig instead of #inject:

ary = example.dig(*p)
ary[target] = 9

# or
example.dig(*p)[target] = 9

That would take care of some of the problematic paths and you'd be left with deciding what to do if ary.nil?.



Related Topics



Leave a reply



Submit