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
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.
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) }
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]]
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]
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