Passing block to select through send method - ruby

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

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

How do I split an array using nil as delimitor?

I'm searching a method for converting:
[1,2,3,nil,4,5,nil,6,7,8,9]
into:
[[1,2,3],[4,5],[6,7,8,9]]
Is there a built-in way to do that in Ruby?
I'd use:
[1,2,3,nil,4,5,nil,6,7,8,9].slice_before{ |e| e.nil? }.map(&:compact)
=> [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
slice_before is really powerful when you want to break an array into chunks, either by searching for a repeating pattern by passing in a regex, or something you can compute via the block. It's much too powerful to summarize right here so take time to read the documentation and play with the examples.
This should work:
array = [1,2,3,nil,4,5,nil,6,7,8,9]
array.inject([[]]) do |result, number|
number ? result.last << number : result << []
result
end
#=> [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
Explanation time :-)
inject starts with an array containing an empty array
for each element, it checks if it's nil
if it isn't, it appends the current number to the previous array
if it is, it creates a new empty array
all this while updating result, which is an array of arrays
-- EDIT --
Checking David's reply I checked Rails implementation of this:
def split(value = nil)
using_block = block_given?
inject([[]]) do |results, element|
if (using_block && yield(element)) || (value == element)
results << []
else
results.last << element
end
results
end
end
If you skip the block implementation, it has the exact same structure of my code. Yay! :)
[1,2,3,nil,4,5,nil,6,7,8,9].split(nil)
Whoops array#split is a Rails method
I found kind of an interesting one. There's probably a way to shorten it:
[1,2,3,nil,4,5,nil,6,7,8,9].chunk {|e| e.nil?}.select {|e| not e[0]}.flatten(1).delete_if {|e| not e}
I would join the array and then split the array.
a =[1,2,3,nil,4,5,nil,6,7,8,9]
a = a.join("-").split("--")
a.map! { |a| a.split("-") }
a.map! {|e| e.map! {|f| f.to_i}}
puts a.inspect
#[[1, 2, 3], [4, 5], [6, 7, 8, 9]]
Made edits (based on comments), to make it an integer once again. Still not a good answer though.

How to make an argument of the method, the array and hash,simultaneously

I need send in method argument which is array and hash simultaneously. But don't know, how. Here is example:
def method(here should be this argument)
end
def show(*a)
p a
if a.length.even? == true
p Hash[*a]
else
p "hash conversion not possible"
end
end
show(1,2,3,4)
show(1,2,3)
output:
[1, 2, 3, 4]
{1=>2, 3=>4}
[1, 2, 3]
"hash conversion not possible"
EDIT:
From comment of OP here is the code OP could use:
def add(*arg)
#entries = {}
arg.each_slice(2) do |a| #entries[a.first] = a.last end
p #entries
end
add(1,2,3,4)
Output:
{1=>2, 3=>4}

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]

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