Ruby - creating a grid - ruby

This is very basic, but can someone explain in plain in english what exactly is happening in this code?
3.times do |row_index|
board[row_index] = []
3.times do |column_index|
board[column_index] = []
board[row_index][column_index] = nil
end
end
end

I will first correct your code and then will show you how to improve it with increasing simplifications.
Presumably the array board is initialized before your code and, because of the extra end is probably in a method, we need:
def initialize_board(n, val)
board = Array.new(n)
n.times do |row_index|
board[row_index] = Array.new(n)
n.times do |column_index|
board[row_index][column_index] = val
end
end
board
end
initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
You see that, to make the method more robust, I've made the board's size (n) and initialization value (val) variables. The method must return board, so we need board as the next-to-last line. (Because it is the last line of the method that is executed, return board is not needed.)
Firstly, since you have board[row_index] =..., board must be created as an array with n elements. That's what Array.new(n) does. Similarly, since you have board[row_index][column_index] =..., board[row_index] (for each value of row_index) must be created as an array with n elements:
board[row_index] = Array.new(n)
This works, but it's not very Ruby-like. Better would be to write:
def initialize_board(n, val)
board = []
n.times do |row_index|
row = []
n.times { |column_index| row << val } # or row.push(val)
board << row # or board.push(val)
end
board
end
initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
Notice that board is initialized to an empty array, is then filled with rows, then board is returned. Similarly, row is initialized to an empty array, filled with copies of val and then appended to board. We can tighten that up by using Enumerable#each_with_object:
def initialize_board(n, val)
n.times.with_object([]) do |row_index, board|
board << n.times.with_object([]) { |column_index, row| row << val }
end
end
initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
We can now use Array.new with a block to create each row with the default value:
def initialize_board(n, val)
n.times.with_object([]) do |row_index, board|
board << Array.new(n) { val }
end
end
initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
and then do it again:
def initialize_board(n, val)
Array.new(n) { Array.new(n) { val } }
end
arr = initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
There's one last thing I'd like to mention. Suppose we set:
arr[1][1] = 'cat'
Then
arr #=> [[nil, nil, nil], [nil, "cat", nil], [nil, nil, nil]]
as expected.
If, however, we had written:
def initialize_board(n, val)
Array.new(n, Array.new(n, val))
end
Then:
arr = initialize_board(3, nil)
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
arr[1][1] = 'cat'
arr #=> [[nil, "cat", nil], [nil, "cat", nil], [nil, "cat", nil]]
which clearly is not what you want.

Try this way in Ruby
Input n defined as size of n x n matrix
Example
if n = 3
Matrix size is 3 x 3
Code
n = gets.chomp.to_i
# Array('A'..'Z').sample is random value from A to Z
matrix = Array.new(n) { Array.new(n) { Array('A'..'Z').sample } }
Output
[["D", "A", "M", "V"], ["X", "Q", "A", "E"], ["P", "D", "L", "S"],
["V", "M", "P", "Z"]]

Related

error when searching through 2d array ruby

I have the following grids (connect four)
grid1 = [
[nil, nil, nil],
[1, nil, nil],
[1, nil, nil],
[1, nil, nil]
]
grid2 = [
[nil, nil, nil],
[nil, nil, 1],
[nil, nil, 1],
[nil, nil, 1]
]
grid3 = [
[nil, nil, nil],
[nil, nil, nil],
[nil, nil, nil],
[1, 1, 1]
]
and this is the method I created to find three 1's in a vertical row and return the next available slot above
def searchArray(array)
array.each_with_index do |y, yi|
y.each_with_index do |x, xi|
if array[yi][xi] != nil && array[yi][xi] == array[yi+1][xi] && array[yi][xi] == array[yi+2][xi]
return v = [yi-1, xi]
end
end
end
end
searchArray(grid2)
When I call the method on grid1, and grid 2 it works great but when I call it on Grid 3 the grid where the 1's are placed on the bottom row I get this error
undefined method `[]' for nil:NilClass
(repl):28:in `block (2 levels) in searchArray'
(repl):27:in `each'
(repl):27:in `each_with_index'
(repl):27:in `block in searchArray'
(repl):26:in `each'
(repl):26:in `each_with_index'
(repl):26:in `searchArray'
(repl):36:in `<main>'
Not sure what's going on
Thanks
You can solve a lot of problems here by simplifying this code using dig:
def search_array(array)
array.each_with_index do |y, yi|
y.each_with_index do |x, xi|
stack = (0..2).map { |o| array.dig(yi + o, xi) }
if (stack == [ 1, 1, 1 ])
return [ yi - 1, xi ]
end
end
end
end
Where dig can poke around and not cause exceptions if it misses the end of the array. Here map is used to quickly pull out an N high stack. You can do 1..2 or 0..4 or whatever is necessary.
Let's take a look at your code, simplified slightly1:
def search_array(array)
array.each_with_index do |y, yi|
y.each_with_index do |x, xi|
return [yi-1, xi] if x != nil && x == array[yi+1][xi] && x == array[yi+2][xi]
end
end
end
You go one row at a time, then for each element in that row, check if that element is not nil and if so, determine whether the two elements below it have the same non-nil value. If you reach the penultimate (next-to-last) row, yi = array.size - 2, you will compare x with array[yi+2][xi], which equals array[array.size][xi], which in turn equals nil[xi]. However, nil has no method [] so an undefined method exception is raised. Pay close attention to those error messages; often, as here, they guide you to the error.
Another problem is that if you found 1's in the first three rows of a column j you would return the index [-1, j], -1 being 0-1. You don't want that either.
I understand that you also wish to determine if dropping a coin in a column results in four-in-a-row horizontally. You could check both vertically and horizontally as follows.
def search_array(arr)
arr.first.each_index do |j|
r = arr.each_index.find { |i| arr[i][j] == 1 }
next if r == 0
r = r.nil? ? arr.size-1 : r-1
return [r,j] if below?(arr,r,j) || left?(arr,r,j) || right?(arr,r,j)
end
nil
end
def below?(arr,r,j)
r < arr.size-3 && (1..3).all? { |i| arr[r+i][j] == 1 }
end
def right?(arr,r,j)
j < arr.first.size-3 && (1..3).all? { |i| arr[r][j+i] == 1 }
end
def left?(arr,r,j)
j >= 3 && (1..3).all? { |i| arr[r][j-i] == 1 }
end
grid4 = [
[nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil],
[nil, nil, 1, nil, nil],
[nil, nil, 1, 1, 1],
[ 1, 1, 1, nil, 1]
]
grid5 = [
[nil, nil, nil, nil, nil],
[nil, nil, nil, nil, nil],
[nil, nil, 1, nil, nil],
[nil, 1, 1, nil, nil],
[nil, 1, 1, nil, 1]
]
search_array grid1 #=> [0, 0] (vertical)
search_array grid2 #=> [0, 2] (vertical)
search_array grid3 #=> nil
search_array grid4 #=> [3, 1] (horizontal)
search_array grid5 #=> [1, 2] (vertical)
Note that if you wish to also check for four-in-a-row diagonnal you could change:
return [r,j] if below?(arr,r,j) || left?(arr,r,j) || right?(arr,r,j)
to
return [r,j] if below?(arr,r,j) || left?(arr,r,j) || right?(arr,r,j) ||
top_left_to_bottom_right?(arr,r,j) || bottom_left_to_top_right?(arr,r,j)
and add the additional methods top_left_to_bottom_right? and bottom_left_to_top_right?.
1. I changed the name of your method to search_array because Ruby has a convention to use snake case for the naming of variables and methods. You don't have to adopt that convention but 99%+ of Rubiests do.
I could suggest a slight different approach, this is not a complete solution, just a start. It should also help to catch the four.
First map the not nil indexes of the grid, let's consider grid3:
mapping = grid3.flat_map.with_index{ |y, yi| y.map.with_index { |x, xi| [xi, yi] if x }.compact }
#=> [[0, 3], [1, 3], [2, 3]]
Then group by first and second element to get the columns and rows:
cols = mapping.group_by(&:first) #=> {0=>[[0, 3]], 1=>[[1, 3]], 2=>[[2, 3]]}
rows = mapping.group_by(&:last) #=> {3=>[[0, 3], [1, 3], [2, 3]]}
Now, if you want to look for three elements in a row or in a column:
cols.keep_if { |_,v| v.size == 3 } #=> {}
rows.keep_if { |_,v| v.size == 3 } #=> {3=>[[0, 3], [1, 3], [2, 3]]}
The first line says there are no columns with three element aligned.
The second line says that row with index 3 has three elements aligned and indexes are [[0, 3], [1, 3], [2, 3]].
Next step it to check that there are no gaps amongst elements. For example in a 4x4 grid you could get also [[0, 3], [1, 3], [3, 3]] which are three elements, but there is a gap in [2, 3],

I need to replace the hash key inside the array with values from a h`ash

I have an array like this
arr = [["ContactCreate", "Test1"], [nil, nil], ["ROW1", "one"],
["ROW2", "four"], ["ROW3", "seven"], ["ROW4", "Ten"],
["ROW5", "thirteen"]]
and a hash like this
h = {"ROW1"=>["id=xxx", "TypeAndWait"], "ROW2"=>["id=xxx", "TypeAndWait"],
"ROW3"=>["id=yyy", "Select"], "ROW4"=>["id=zzz", "SelectAndWait"],
"ROW5"=>["id=aaa", "Check"]}
I want to replace first element of the each subarray with its hash value, provided it is a hash key. The resultant array should be as follows.
[["ContactCreate", "Test1"], [nil, nil], [["id=xxx", "TypeAndWait"], "one"],
[["id=xxx", "TypeAndWait"], "four"], [["id=yyy", "Select"], "seven"],
[["id=zzz", "SelectAndWait"], "Ten"], [["id=aaa", "Check"], "thirteen"]]
For example, "ROW1" in the third subarray should be replaced by h["ROW1"].
Is there any easy way to achieve this?
This should work (arr is your array, h is your hash)
arr.map do |x, y|
[h[x] || x, y]
end
h.default_proc = Proc.new { |h,k| k }
arr.map { |e1,e2| [h[e1], e2] }
This approach could also be used as follows.
arr = [["ContactCreate", "Test1", "Test2"], ["ROW1", nil], [1, "ROW2", "four"]]
arr.map { |a| a.map { |e| h[e] } }
#=> [["ContactCreate", "Test1", "Test2"], [["id=xxx", "TypeAndWait"], nil],
# [1, ["id=xxx", "TypeAndWait"], "four"]]
The default proc merely causes h[k] to return k if h does not have a key k. See Hash#default_proc=.
If one does not wish to modify h by attaching a default proc, one could attach the default proc to h.dup and use the dup in place of h.

translate java 2d array into ruby

How would I write this java code into ruby:
String[] [] Score = new String [row] [col];
Score[rCount][cCount] = num;
I thought it would as simple as:
score=[]
score[rcount][ccount]=num
But I keep getting "undefined method `[]=' for nil:NilClass (NoMethodError)"
Sorry, I don't know java, but have a look at the class methods Array#new and Array::[], and the instance methods Array#[]= and Array#[]. Here are some examples that should answer your question (and other questions that may be sparked, hopefully):
Array.new #=> []
[] #=> [] # shorthand for above
a = Array.new(5) { [] } #=> [[], [], [], [], []]
a[0][0] = 2
a #=> [[2], [], [], [], []]
a[3][2] = 4
a #=> [[2], [], [], [nil, nil, 4], []]
a[1] << 1
a #=> [[2], [1], [], [nil, nil, 4], []]
a[1] << 2
a #=> [[2], [1, 2], [], [nil, nil, 4], []]
a[1] << 3 << 4
a #=> [[2], [1, 2, 3, 4], [], [nil, nil, 4], []]
a[2] << [4,5]
a #=> [[2], [1, 2, 3, 4], [[4, 5]], [nil, nil, 4], []]
a[4].concat([4,5])
a #=> [[2], [1, 2, 3, 4], [[4, 5]], [nil, nil, 4], [4, 5]]
a = Array.new(3) { Array.new(3) }
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
a[1][2] = 4
a #=> [[nil, nil, nil], [nil, nil, 4], [nil, nil, nil]]
We could also write the default as a second argument:
a = Array.new(3,[]) #=> [[], [], []]
but that can be problematic:
a[0][0] = 'cat'
a #=> [["cat"], ["cat"], ["cat"]]
as is:
a = Array.new(3,Array.new(2)) #=> [[], [], []]
#=> [[nil, nil], [nil, nil], [nil, nil]]
a[0][0] = 'cat'
a #=> [["cat", nil], ["cat", nil], ["cat", nil]]
since each element of a is the same array.
Note that Ruby provides a convenience for writing certain methods that is commonly referred to as "syntactic sugar". If, for example, you write a = [1,2,3], Ruby will interpret that as a = Array.[](1,2,3) (and you could write it that way), the class method being Array::[]. Similarly, if a equals [1,2,3], a[1] = 'cat' is decoded as a.[]=(1, 'cat') and a[1] #=> 'cat' is a.[](1). Similarly, h = {} translates to h = Hash.new and so on.
Note that Ruby does not have a concept of "multidimensional arrays". For more on that you may wish to see a comment a left on this question.
Firstly, ruby programmers use snake case. Capital letter is using for class names.
Secondly, your problem happens just because
score[rcount] == nil # true
If you want to have an access to second dimension elements you need to initialize line as array:
score[rcount] = []
Now you can set second dimension element
score[rcount][ccount] = num

Ruby check array, return the indexes, which data is exist

How can I check if there's a data that not nil in an array, and then return the index of that data?
Example:
myary = [nil, nil, 300, nil, nil] # <= index 2 is 300
now is there a method to get the value 2? As we know the index 2 is 300 and not nil.
I need to get the index not the value. And moreover there probably will ot only one element that is not nil, perhaps the array could be like this
myotherary = [nil, nil, 300, 400, nil] # <= index 2,3 = 300,400
now for this I need to get 2 and 3 value, is this posibble?
Okay thank you very much, I appreciate all answer.
P.S : Please no flaming, if you don't want to help then just leave, I have spent some time to solve this matter and not succeed. I'm not going to ask here if I can solve it by myself. I had enough of them who not helping, instead asking "what method have you tried?" or write something else that actually not helping but harrasing.
You can use map.with_index:
myary.map.with_index { |v, i| i if v }.compact
# => [2]
myotherary.map.with_index { |v, i| i if v }.compact
# => [2, 3]
I would be inclined to use Enumerable#select in part because it reads well; the word "select" describes what you want to do.
Code
For just the indices:
def indices_only(arr)
arr.size.times.select { |i| arr[i] }
end
If it would be more useful to return both non-nil values and corresponding indices:
def values_and_indices(arr)
arr.each_with_index.select(&:first)
end
Examples
arr1 = [nil, nil, 300, nil, nil]
arr2 = [nil, nil, 300, 400, nil]
indices_only(arr1) #=> [2]
indices_only(arr2) #=> [2, 3]
values_and_indices(arr1) #=> [[300, 2]]
values_and_indices(arr2) #=> [[300, 2], [400, 3]]

Locate a string in an array of strings

I would like to find the location in an array of all strings of any given word.
phrase = "I am happy to see you happy."
t = phrase.split
location = t.index("happy") # => 2 (returns only first happy)
t.map { |x| x.index("happy") } # => returns [nil, nil, 0, nil, nil, nil, 0]
Here's a way
phrase = "I am happy to see you happy."
t = phrase.split(/[\s\.]/) # split on dot as well, so that we get "happy", not "happy."
happies = t.map.with_index{|s, i| i if s == 'happy'} # => [nil, nil, 2, nil, nil, nil, 6]
happies.compact # => [2, 6]
phrase = "I am happy to see you happy."
phrase.split(/[\W]+/).each_with_index.each_with_object([]) do |obj,res|
res << obj.last if obj.first == "happy"
end
#=> [2, 6]

Resources