1

I want a 2d array to be initialized as follows

1 0 0 0
0 2 0 0
0 0 3 0
0 0 0 4

When input string "1234" is given.

My function to do this is as follows

def fun(str)
    maxlength = Array.new(str.length,Array.new(str.length,0))
    (0..str.length-1).each do |i|
        maxlength[i][i] = str[i].to_i
    end
    print maxlength
end

print fun("1234")

this gives me

1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4

Which is not what I want.

How to get the output I want ?

1
  • 1
    Put a new array in each of the first array's references, not the same one as you're doing now. Commented Mar 16, 2015 at 19:01

3 Answers 3

7

I suggest you use the class method Matrix::diagonal:

require 'Matrix'

str = "1234"

Matrix.diagonal(*(str.chars.map(&:to_i))).to_a
  # => [[1, 0, 0, 0],
  #     [0, 2, 0, 0],
  #     [0, 0, 3, 0],
  #     [0, 0, 0, 4]] 

Another way:

Array.new(str.size) {|i| Array.new(str.size) {|j| (i==j) ? str[i].to_i : 0}}
  # => [[1, 0, 0, 0],
  #     [0, 2, 0, 0],
  #     [0, 0, 3, 0],
  #     [0, 0, 0, 4]] 
Sign up to request clarification or add additional context in comments.

1 Comment

beautiful. as a newbie to ruby, the second solution demonstrated the expressiveness. it's sort-of like list -comprehension in python. only more C like.
5

The biggest problem here is that you're not creating a two dimensional array like you think you are, but instead you're creating two arrays. This is because you're passing in a singular array as a default, not a block that can generate them.

What you were expecting was this:

array1 = [ array21, array22, array23, array24 ]

What you were actually getting is this:

array1 = [ array2, array2, array2, array2 ]

This is easily fixed by converting the last argument to a block:

def fun(str)
    maxlength = Array.new(str.length) { Array.new(str.length,0) }
    str.chars.collect(&:to_i).each_with_index do |v,i|
        maxlength[i][i] = v
    end
    print maxlength
end

print fun("1234")

I've also switched to using chars which splits up the string as you want.

So the problem was that you were setting the positions correctly, but as all the second level arrays were the same array, you didn't get the result you were expecting.

Update: Added each_with_index from Chris's answer which makes this work with arbitrary numbers.

1 Comment

thanks for taking the time to explain what I was doing wrong.
2

Another one-liner for you:

"1234".chars.map.with_index {|v, i| Array.new(4, 0).tap {|a| a[i] = v.to_i } }

This just creates N arrays, one for each character in the string, and sets the ith index of each array to the value of that character in the string.

Edit: Another fun solution:

"1234".chars.map.with_index {|c, i| [c.to_i].fill(0, 1..4).rotate(-i) }

This creates four arrays consisting of [value, 0, 0, 0] and then uses Array#rotate to shift the value into the right position.

And another solution, which exploits the fact that there are four 0 values between each pair of non-zero values:

"1234".chars.flat_map {|c| [c.to_i].fill(0, 1..4) }.each_slice(4).take(4)

3 Comments

Was just going to say chars is where it's at for this but you beat me to it on an edit. The with_index part is actually missing in the original, so it only worked by coincidence. Thanks for pointing that out.
what's happening here ? i know what map is, but that's about it. i don't see the lambda that it's taking or the list it's working on.
@anu map creates an enumerator over the receiver. with_index amends the enumerator to pass both the value and index to the block. Array.new(4, 0) creates a new array of 4 elements, where each element is 0. tap passes the tapped object to the block, then returns the tapped object, letting us operate on it before returning it to the map block. In this case, we tap the newly-created array to set its ith element to the integer value of the character passed to map.

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.