Creating and iterating a 2d array in Ruby - ruby

I have very little knowledge about Ruby and cant find a way to create 2d array. Can anyone provide me some snippets or information to get me started?

a = [[1, 2], [3, 4]]
a.each do |sub|
sub.each do |int|
puts int
end
end
# Output:
# 1
# 2
# 3
# 4
or:
a = [[1, 2], [3, 4]]
a.each do |(x, y)|
puts x + y
end
# Output:
# 3
# 7

The easiest way to create a 2d array is by the following:
arr1 = Array.new(3) { Array.new(3)}
The code above creates a 2D array with three rows and three columns.
Cheers.

irb(main):001:0> a = []
=> []
irb(main):002:0> a1 = [1, 2]
=> [1, 2]
irb(main):003:0> a2 = [3, 4]
=> [3, 4]
irb(main):004:0> a.push a1
=> [[1, 2]]
irb(main):005:0> a.push a2
=> [[1, 2], [3, 4]]
irb(main):006:0> a
=> [[1, 2], [3, 4]]
irb(main):007:0> a[0]
=> [1, 2]
irb(main):008:0> a[0][1]
=> 2

Ruby doesn't have the concept of 2-dimensional arrays like C does. Arrays in Ruby are dynamic -- meaning you can resize them a will. They can contain any object or value in each "slot" - including another Array!
In the examples given by #JunaidKirkire and #simonmenke, you have an array which has arrays for its values. You can access the values using the syntax similar to C - but you could also have the case where one slot is an Array and another is just a number, or a String, or a Hash...
You may want to work through a Ruby tutorial to get a better idea of how it works. I like RubyMonk but there are other good ones out there as well.

Creating a 2d array in Ruby
In ruby, every method accepts a block.
two_d_array = Array.new(3) do
Array.new(3) do
0
end
end
The same can be written In oneline (macro style)
two_d_array = Array.new(3) { Array.new(3) { 0 } }
Output
[
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
Iterating a 2d array in Ruby
I can think of three ways.
1: Using range
(0...two_d_array.size).each do |i|
(0...(two_d_array[i].length)).each do |j|
puts two_d_array[i][j]
end
end
2: Using for
for i in (0...two_d_array.size)
for j in (0...two_d_array[i].length)
puts two_d_array[i][j]
end
end
3: Using Each_with_index method
two_d_array.each_with_index do |sub_array, i|
sub_array.each_with_index do |item, j|
puts two_d_array[i][j]
end
end

Related

How to find difference of array items in Ruby

I am trying to find difference of two array items. For example I am expecting [-1, -4], [-2, 4], [1, -2] from [arr[i],arr[i+1]].transpose.map{|x| x.reduce(:-)}. But I get an error, `transpose': no implicit conversion of nil into Array (TypeError).
myarr =[]
i=0
arr = [[1,1],[2,5],[4,1],[3,3]]
while i < arr.length
myarr = [arr[i],arr[i+1]].transpose.map{|x| x.reduce(:-)}.dosomething
i += 1
end
def dosomething
...
end
What am I doing wrong here?
New to Ruby.
You might want to try each_cons:
arr = [[1,1],[2,5],[4,1],[3,3]]
def dosomething(myarr)
puts myarr.to_s
end
arr.each_cons(2) do |pairs|
myarr = pairs.transpose.map{|x| x.reduce(:-)}
dosomething(myarr)
end
# [-1, -4]
# [-2, 4]
# [1, -2]
Another way to calculate the argument for do_something is to make use of Ruby's Matrix class and Array#zip:
require 'matrix'
arr = [[1,1],[2,5],[4,1],[3,3]]
diff = arr[0..-2].zip(arr.drop(1)).map { |a,b| (Matrix[a] - Matrix[b]).to_a }
#=> [[[-1, -4]], [[-2, 4]], [[1, -2]]]

Take all items with enumerable#take

How can I Enumerable#take all the things?
arr = [1, 2, 3]
# Works
arr.take(1)
# Gives RangeError: float Inf out of range of integer
arr.take(Float::INFINITY)
# Gives RangeError: float Inf out of range of integer
arr.take(1.0/0.0)
# RangeError: bignum too big to convert into `long'
arr.take(1000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000)
# TypeError: no implicit conversion from nil to integer
arr.take(nil)
If it's not possible to take all items with Enumerable#take, then I'd have to have the convoluted code in display_results_allowing_all_objects rather than the simple code in display_results.
MAX_ROWS = 1
# Simple code: Only two lines long.
def display_results(results)
results_to_display = results.take(MAX_ROWS)
puts results_to_display.map{|result| result.join("\t")}.join("\n")
end
results = [["Foo", 1], ["Bar", 2], ["Baz", 3]]
display_results(results)
NEW_MAX_ROWS = Float::INFINITY
# Convoluted mess: six lines long
def display_results_allowing_all_objects(results)
results_to_display = if NEW_MAX_ROWS == Float::INFINITY
results
else
results_to_display = results.take(NEW_MAX_ROWS)
end
puts results_to_display.map{|result| result.join("\t")}.join("\n")
end
display_results_allowing_all_objects(results)
You can use Enumerable#take_while to take all the items
$> arr.take_while { true }
# => [1, 2, 3]
We can do the [0..-1]. But with .. you can't get 0 items while with ... you can't get all of them. If you can deal with inability to get 0 results, use .., but you'll have to do -1, so the 0 will mean the all results:
results_to_display = results[0 .. rows_to_take-1]
You could cast #to_a which would take everything:
arr = [1, 2, 3]
arr.to_a
#=> [1, 2, 3]
(1..4).lazy.to_a
#=> [1, 2, 3, 4]

Replace array elements with map

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?
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
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.
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]>

Number of arguments in a ruby block

I'm new to Ruby, but not to languages that allow lambda's, such as groovy. So I saw this example:
myArray.product(otherArray).reject{|i,j| i > j}
in a ruby code block, and I hadn't seen this block take 2 arguments before, but when I went to look at the documentation I can only see the documentation that says that it takes 1 argument. I looked at the same for the enumerable class, but that doc only shows 1 argument also.
I understand that it works, I guess I was hoping that there was an easier way to determine how many arguments it takes other then a guess and test method. How can I tell how many arguments a block takes in Ruby?
This works because Ruby supports destructuring.
Destructuring allows you to bind a set of variables to a corresponding set of values anywhere that you can normally bind a value to a single variable.
This allows the following to hold true:
arr = [1, 2]
x = arr
x == [1, 2] # true
y, z = arr
y == 1 # true
z == 2 # true
You can see from the following code that destructuring in arguments to blocks isn't unique to the built-in methods that take a block:
def my_method(arr)
yield arr
end
my_method([1, 2, 3]) {|x| puts x.inspect }
# => [1, 2, 3]
my_method([1, 2, 3]) {|x, y, z| puts x.inspect }
# => 1
Check out Destructuring with Ruby for more information.
You can do some interesting restructuring in block parameters, depending on the structure of your array:
[[1, 2], [3, 4], [5, 6], [7, 8]].reject {|x,y| y == 8 }
#=> [[1, 2], [3, 4], [5, 6]]
You can group them in parentheses:
[ [[1,2],3], [[1,3],6] ].select {|(x,y),z| x == 1 && z == 3 }
#=> [ [[1,2],3] ]
You can also use the splat operator for various things, like dealing with variable-length subarrays:
[[:a,:b,2,3,4,5,6], [:c,:d,7,8,9]].each {|x,y,*numbers| puts numbers.inspect }
#=> [2,3,4,5,6]
#=> [7,8,9]
Ruby is flexible in how it interprets the arguments; here is a similar example, with one and then two arguments:
[1, 3].product([2, 4]).reject {|a| a.first > a.last }
=> [[1, 2], [1, 4], [3, 4]]
[1, 3].product([2, 4]).reject {|a,b| a > b }
=> [[1, 2], [1, 4], [3, 4]]
The rule of thumb here is that you can treat the arguments either as a composite object, or as individual elements in a collection. E.g.,
[1, 2, 3].tap {|a,b,c| puts [a,b,c].inspect }
[1, 2, 3]
...
[1, 2, 3].tap {|a,b| puts [a,b].inspect }
[1, 2]
...
[1, 2, 3].tap {|a| puts a.inspect }
[1, 2, 3]

Ruby two dimensional array: finding an object's coordinates

Assume, I have a two dimensional array A, and it's stated that somewhere inside it there's an object my_element. What's the quickest way to find out its coordinates? I am using Ruby 1.8.6.
This is one way. I'm not sure it's the quickest, though.
class Array
def coordinates(element)
each_with_index do |subarray, i|
j = subarray.index(element)
return i, j if j
end
nil
end
end
array = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]
array.coordinates(3) # => [0, 2]
array.coordinates(9) # => [2, 2]
array.coordinates(42) # => nil

Resources