How to find difference of array items in Ruby - 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]]]

Related

Ruby Getting a max value out of a newly created array in one function

I want my function to return the longest Array within a nested array (including the array itself) so
nested_ary = [[1,2],[[1,2,[[1,2,3,4,[5],6,7,11]]]],[1,[2]]
deep_max(nested_ary)
=> [1,2,3,4,[5],6,7,11]
simple_ary = [1,2,3,4,5]
deep_max(simple_ary)
=> returns: [1,2,3,4,5]
I created a function to collect all arrays. I have to get the max value in another function.
my code:
def deep_max(ary)
ary.inject([ary]) { |memo, elem|
if elem.is_a?(Array)
memo.concat(deep_max(elem))
else
memo
end }
end
This gives me what I want:
deep_max(nested_ary).max_by{ |elem| elem.size }
Is there a way to get this max inside of the function?
def deep_max(arr)
biggest_so_far = arr
arr.each do |e|
if e.is_a?(Array)
candidate = deep_max(e)
biggest_so_far = candidate if candidate.size > biggest_so_far.size
end
end
biggest_so_far
end
deep_max [[1, 2], [[1, 2, [[1, 2, 3, 4, [5], 6, 7, 11]]]], [1, [2]]]
#=> [1, 2, 3, 4, [5], 6, 7, 11]
You can unroll it:
def deep_max(ary)
arys = []
ary = [ary]
until ary.empty?
elem = ary.pop
if elem.is_a?(Array)
ary.push(*elem)
arys.push(elem)
end
end
arys.max_by(&:size)
end
Or you can cheat, by introducing an optional parameter that changes how your recursion works on top level vs how it behaves down the rabbit hole.

Passing block to select through send method

my_array = [[1, 'foo_parent', nil], [2,'bar_is_son_of_foo', 1], [3, 'zok_is_son_of_bar', 2]]
def children_block
Proc.new do |c|
if c.is_a? Array
c[2] == self[0]
end
end
end
my_array.send(:select) &children_block
gives me ArgumentError: wrong number of arguments (0 for 1..4)
You can do something like this to pass a block to select via send.
my_array.send(:select, &children_block)
Here is a working sample:
my_array = [[1, 'foo_parent', nil], [2,'bar_is_son_of_foo', 1], [3, 'zok_is_son_of_bar', 2]]
def children_block
Proc.new do |c|
p c
end
end
p my_array.send(:select, &children_block)
#=> [1, "foo_parent", nil]
[2, "bar_is_son_of_foo", 1]
[3, "zok_is_son_of_bar", 2]
The problem you are trying to solve can be also solved using:
my_array.select {|i| my_array.find {|j| j.first == i.last} }
or
my_array.select {|i| my_array.find {|j| i.first == j.last} }
depending on which elements you are interested in.
PS: There was another question today with similar issue with respect to passing block. First part of my answer is derivation of that question's answer
Blocks and lambdas/procs aren't the same, you can't just replace one with the other. The following should guide you in the right direction
my_array.send(:select) { |element| filter_somehow(element) }

How do I find the location of an integer in an array of arrays in ruby?

Given:
a = [[1,2,3,4],
[1,2,3,7],
[1,2,3,4]]
What do I need to do to output the location of the 7 as (1,3)?
I've tried using .index to no avail.
require 'matrix'
a = [[1, 2, 3, 4],
[1, 2, 3, 7],
[1, 2, 3, 4]]
Matrix[*a].index(7)
=> [1, 3]
If your sub-arrays are all the same width, you can flatten it into a single array and think of the position as row_num * row_width + col_num:
idx = a.flatten.index(7)
row_width = a[0].length
row = idx / row_width
col = idx - (row * row_width)
puts [row, col] # => [1, 3]
Or you could just iterate it to find all matches:
def find_indices_for(array, value)
array.with_object([]).with_index do |(row, matches), row_index|
matches << [row_index, row.index(value)] if row.index(value)
end
end
find_indices_for(a, 7) # => [[1, 3]]
find_indices_for(a, 2) # => [[0, 1], [1, 1], [2, 1]]
each_with_index works pretty well here:
def locator(array, number)
locations = Array.new
array.each_with_index do |mini_array, index|
mini_array.each_with_index do |element, sub_index|
locations << [index, sub_index] if element == number
end
end
locations
end
Now, locator(array, number) will return an array of containing all the locations of number in array.
def locs2D(a,e)
a.size.times.with_object([]) do |row,arr|
row.size.times { |col| arr << [row,col] if a[row][col] == e }
end
end
locs2D(a,7) #=> [[1, 3]]
locs2D(a,3) #=> [[0, 2], [1, 2], [2, 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]

Creating and iterating a 2d array in 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

Resources