2

I have two arrays:

@a = [ 
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]
@b = [a, b, c]

I need to replace n-th column in a with b like:

swap_column(0)
#=> [a, 2, 3]
    [b, 5, 6]
    [c, 8, 9]

(This is for using Cramer's rule for solving equations system, if anybody wonders.)

The code I've come up with:

  def swap_column(n)
    @a.map.with_index { |row, j| row[n] = @b[j] }
  end

How do I get rid of assignment here so that map returns the modified matrix while leaving @a intact?

0

3 Answers 3

2

What you wanted is dup. Also, you had the return value of the map.with_index block wrong.

def swap_column(i)
  @a.map.with_index{|row, j| row = row.dup; row[i] = @b[j]; row}
end

or

def swap_column(i)
  @a.map.with_index{|row, j| row.dup.tap{|row| row[i] = @b[j]}}
end
Sign up to request clarification or add additional context in comments.

Comments

1

The answer by sawa is good and the main point is you need to dup your inner arrays for this to work properly. The only reason for this additional post is to point out that often when you are using with_index so that you can directly 1:1 index into another array you can simplify the code by using zip.

def swap_column(n)
  @a.zip(@b).map {|r,e| r.dup.tap{|r| r[n] = e}}
end

What zip does is combine your two arrays into a new array where each element is an array made of the two corresponding elements of the initial arrays. In this case it would be an array of an array and an element you want to later use for replacement. We then map over those results and automatically destructure each element into the two pieces. We then dup the array piece and tap it to replace the nth element.

Comments

0

You can use transpose to do the following:

class M
  attr :a, :b

  def initialize
    @a = [[1,2,3],
          [4,5,6],
          [7,8,9]
        ]
    @b = [:a, :b, :c]
  end

  def swap_column(n)
    t = @a.transpose
    t[0] = @b
    t.transpose
  end

end

m = M.new
=> #<M:0x007ffdc2952e38 @a=[[1, 2, 3], [4, 5, 6], [7, 8, 9]], @b=[:a, :b, :c]>
m.swap_column(0)
=> [[:a, 2, 3], [:b, 5, 6], [:c, 8, 9]]
m  # m is unchanged
=> #<M:0x007ffdc2952e38 @a=[[1, 2, 3], [4, 5, 6], [7, 8, 9]], @b=[:a, :b, :c]>

1 Comment

Isn't transpose an overkill? Two of them here, actually. I heard it can be quite slow on large arrays.

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.