hackerrank question - use of proc in ruby - arrays

problem: Create a Proc p that will check whether a given array of elements are nil or not. Use .nil? to evaluate elements. Print 'true' if elements are nil, and 'false' if the elements has a value
Issue: I came up with below solution but its giving me only one value as true instead of checking for each value of array , please help in correcting below code:
Code:
def check_nill(array1)
p = Proc.new{ |num| num.nil?}
c = array1.any?(&p)
return c
end
array1 = [2,nil,8]
result = check_nill(array1)
puts "#{ result1 }"
Output: true

Create a Proc to check if a value is a nil or not.
my_proc = Proc.new { |num| num.nil? }
Iterate over the array using the above proc
array1 = [2,nil,8]
array1.map { |x| my_proc.call(x) }
You will get the below result
[false, true, false]

Your solution doesn't work because the method you're using, Array#any?, returns true if any of the values in the array is nil (due to your p). What I understood is that you want a solution that will return if each element is nil or not.
A possible solution is:
# You can create a Proc `p` that'll map an array to the results of `nil?`.
p = Proc.new { |ary| ary.map(&:nil?) }
# You can apply a Proc by using the method `call`, or by doing:
# p.([1, nil, 2])
# p[[1, nil, 2]]
p.call([1, nil, 2]) # => [false, true, false]

Related

How can I create a Proc to checking whether the elements of an array are nil or not?

I'm trying to solve this assignment:
Create a Proc that will check whether a given array of elements are nil or not. Use .nil? to evaluate elements. Print 'true' if the elements are nil and 'false' if the element has a [truthy] value.
This is my attempt:
def check_nil(array1)
p = Proc.new {|x| x.nil?}
res= p.call(array1)
if res == true
return "true"
else
return "false"
end
end
array1 = [{},nil,[]]
result = check_nil(array1)
puts "#{result}"
Here actually, the output should be "true" but this code gives "false" as output. Can someone explain the reason?
Your method currently checks whether the given object is nil:
check_nill(nil) #=> "true"
check_nill([]) #=> "false"
check_nill(123) #=> "false"
Note that this object can be anything, so your argument name array1 is somehow misleading for this use case. (you might also want to rename the method to check_nil, i.e. with one l)
Here actually, the output should be "true" [...]
I assume that you actually want to check whether any of the array's elements meets a condition, i.e. if the array contains nil. You can use any? with a block for this. From within the block, you can call your proc:
prc = Proc.new { |x| x.nil? }
[{}, nil, []].any? { |element| prc.call(element) }
#=> true
Which can be shortened by converting the proc to a block:
prc = Proc.new { |x| x.nil? }
[{}, nil, []].any?(&prc)
#=> true
You can even get rid of your custom proc and use Symbol#to_proc instead:
[{}, nil, []].any?(&:nil?)
#=> true
There's also all? which checks whether all elements meet the condition, e.g.:
[{}, nil, []].all?(&:nil?)
#=> false
[nil, nil, nil].all?(&:nil?)
#=> true
If I understand the question correctly, you are trying to check whether all the array elements are nil/blank/false or not. If there is any non-nil value present in the array, you want to return true, else false.
Here is how you can determine this:
array1 = [{}, nil, []]
array1.all?(&:blank?) # this returns true
array2 = [{}, nil, [], 1]
array1.all?(&:blank?) # this returns false
[nil,nil,nil].all? nil No proc.
Truthiness in Ruby
Other issues aside, {} and [] respond to #nil? but are actually truthy since they are neither nil nor false.
[].nil?
#=> false
{}.nil?
#=> false
In Ruby, the only falsey values are nil and false. However, Array and Hash objects do respond to #empty? with a Boolean, which isn't really the same thing as nil.
[].empty?
#=> true
{}.empty?
#=> true
[1].empty?
#=> false
{foo: 1}.empty?
#=> false
Why Use Proc Objects in the First Place
The real point of Proc objects and lambas in Ruby is to create closures that carry their execution context with them even when the original binding has gone out of scope. They aren't really first-class functions, and methods are generally more flexible, so you should generally use a Proc or lambda primarily to pass around a closure that carries variables outside their normal scope.
The Quick Answer: Using a Proc to Return a "Truth Table" Hash
The simplest way to return a "truth table" from a Proc that reports on each element will look something like this:
prc = proc { |array| array.zip(array.map(&:nil?)).to_h }
prc.call [1, 2, nil, 4]
#=> {1=>false, 2=>false, nil=>true, 4=>false}
Getting Fancy with Calling Semantics
In Ruby 3.1.2, you could also create a Proc that can handle an Array or multiple arguments, and return a Hash telling you which of the values are nil.
prc = proc { |*array| array.zip(array.map(&:nil?)).to_h }
prc [1, 2, nil, 4]
#=> {1=>false, 2=>false, nil=>true, 4=>false}
prc[1, 2, nil, 4]
#=> {1=>false, 2=>false, nil=>true, 4=>false}
prc.call(*[1, 2, nil, 4])
#=> {1=>false, 2=>false, nil=>true, 4=>false}
prc.(1, 2, nil, 4)
#=> {1=>false, 2=>false, nil=>true, 4=>false}
Note that the use of variadic calling semantics can be a bit tricky, though, as Proc#[] and Proc#call will treat the collected Array as a single argument unless you splat the Array during the call. For example:
prc = proc { |*array| array.zip(array.map(&:nil?)).to_h }
prc.call [1, 2, nil, 4]
#=> {[1, 2, nil, 4]=>false}
Use a Lambda to Enforce Arity
If you want to force the user to pass only a single argument, and maybe check if it's actually an Array while you're at it, then it's probably better to use a lambda. Lambdas enforce arity, and if you don't trust that you're being passed an Array or a duck-typed object that can #respond_to? typical Array methods, you could do something like this:
check_elements_for_nil = lambda do |arg|
raise TypeError, "expected Array, got #{arg.class}" unless
arg.kind_of? Array
arg.zip(arg.map(&:nil?)).to_h
end
# #raises [ArgumentError] wrong number of arguments
check_elements_for_nil.call(1, 2, 3)
# #raises [TypeError] expected Array, got Hash
check_elements_for_nil.call({foo: 1, bar: 2, baz: 3})
# #return [Hash] truth table for nil values
check_elements_for_nil.call([1, 2, nil, 4])
#=> {1=>false, 2=>false, nil=>true, 4=>false}
More Fun with Stabby Lambdas and Closures
You could make it shorter, too, using a one-liner with a stabby lambda and chaining the input to the lambda definition itself:
->(a) {a.zip(a.map(&:nil?)).to_h}.([1, 2, nil, 4])
#=> {1=>false, 2=>false, nil=>true, 4=>false}
but the practical benefits of this are pretty much zero since you could do the same thing without the lambda. However, since procs and lambdas are closures, it is potentially useful to use something like the following, which demonstrates how to use a lambda with no explicitly-passed arguments:
# method with a hard-coded local variable
#
# #return [lambda] that closes over local variables
def create_a_scope_gate_and_return_a_lambda
array = [1, 2, nil, 4]
->{array.zip(array.map(&:nil?)).to_h}
end
# #note This method doesn't have access to the array
# defined as a local variable in the method above.
# It's like magic!
# #return [Hash] but only because we know what calling
# the lambda will return; pragmatically it could be
# whatever calling +proc_or_lambda+ returns
def call_closure_with_out_of_scope_var(proc_or_lambda)
proc_or_lambda.call
end
a_lambda = create_a_scope_gate_and_return_a_lambda
call_closure_with_out_of_scope_var(a_lambda)
#=> {1=>false, 2=>false, nil=>true, 4=>false}
This works without any explicit arguments to the lambda at all, because the local array variable is in scope when the lambda is defined, and the lambda carries that value with it out through the scope gate of the defining method, and in through the scope gate of a second method.

What's the way to check if all the elements in an array are nil? [duplicate]

This question already has answers here:
How do I check if there's a nil set or not in an array?
(5 answers)
Closed 4 years ago.
I would like to know if there's anything except nil values in an array.
arr = [nil, nil, nil, nil] # => true
arr = [nil, 45, nil, nil] # => false
There could be any values of any types (not only 45).
Use the Enumerable#all? method:
p arr.all? { |x| x.nil? }
Or
p arr.all?(&:nil?)
As #Stefan suggested,
p arr.all?(NilClass) #works only for Ruby 2.5
you could do arr.compact.empty?, compact gets rid of all the nil for you
you could read here at ruby guides to find about all the methods on Array class
You can also use #any? method for array
[nil, 45].any?
=> true
[nil, nil].any?
=> false
From the documentation:
If the block is not given, Ruby adds an implicit block of {|obj| obj} (that is any? will return true if at least one of the collection members is not false or nil.
Note: This won't work if false boolean values are present.
[nil, false].any?
=> false # It should return `true`
Other options would be:
arr = [nil, nil, 45]
arr.count(nil) == arr.length
=> false
(arr - [nil]).empty?
=> false

array.nil? when array having only multiple `nil` values

Consider an array having only one value nil
array = [nil]
Is there any better way to check whether an array is nil or not, like array.nil??
This works:
array == [nil]
But what if there are multiple nil values in the array?
array = [nil, nil, nil]
Below is the requirement:
array = [1, 2] if array.nil?
array.nil? should also give 'true' when array = [nil, nil, nil]
You can use Array#any? to check if the array contains at least one value that is not false or nil:
array = [1,2] unless array.any?
If array is allowed to contain false and you are interested only in nil then Array#any? needs a block:
array = [1,2] unless array.any?{|i| !i.nil?}
Update
As #mu-is-too-short suggests, a better version is:
array = [1,2] if array.all?(&:nil?)
It does exactly what you need: Enumerable#all? returns true if the block returns a true-ish value for all elements of the array.
One option is to uniquify your array and then do what you were already doing:
array.uniq == [nil]
So if array is any amount of nils it will be true. On the other hand:
array.nil?
Checks whether array itself is nil, which is not the same as an array containing nil elements.
One of possible ways is to remove nil values with .compact and check if the result is empty? .
array = [1, 2] if array.compact.empty?

How do I strip off nil elements from the end of an array if all my elements are nil?

I'm using Ruby 2.4. I want to strip off nil elements from the end of an array, so I'm using
row_data.pop until row_data.last
but if the array only contains nil elements, this seems to cause some kind of infinite loop because the call never returns. How do I account for the fact that the array might contain all nil elements?
Just add an extra check to see if the array is empty.
row_data.pop until row_data.last || row_data.empty?
You can use Array#rindex to obtain the right-most non-nil entry (or determine that every element in the array is nil).
def kill_nils_at_end(arr)
ndx = arr.rindex(&:itself)
ndx ? arr[0..ndx] : []
end
kill_nils_at_end [1,nil,1,nil,nil,nil]
#=> [1, nil, 1]
kill_nils_at_end [nil,nil,nil,nil,nil,nil]
#=> []
This does not mutate the original array. If you wish to modify the array in place, change the penultimate line to
arr.replace(ndx ? arr[0..ndx] : [])
Try this
Most readable
arr = arr.reverse.drop_while(&:nil?).reverse
Most efficient
arr.slice!(0..arr.rindex { |each| nil != each }.to_i)
If all nils are to be removed, try this:
[1, nil, 3, nil, nil].compact #= [1,3]
see Map and Remove nil values in Ruby

shovel eight objects into each array index ruby

Is there a way to refactor this code? The first snippet is what I currently have and the second is the logic I am trying to churn out.
count = 0
until count >= board.length
if board[count] == nil
board[count] = [nil, nil, nil, nil, nil, nil, nil, nil,]
end
count += 1
end
board
On my 4th line, I want to do something like
board[count] = (8.times { board[count] << nil })
I know it is just about as long. I am just curious or want to flush my logic out...thanks!!
Try to use Array's constructor
Array.new(8)
=> [nil, nil, nil, nil, nil, nil, nil, nil]
Array.new(8, 42)
=> [42, 42, 42, 42, 42, 42, 42, 42]
and pass a block if you need an object and don't want that each instance is the same
Array.new(8) { Hash.new }
=> [{}, {}, {}, {}, {}, {}, {}, {}]
Besides shortening the assignment to board[count] = Array.new(8), other parts can be written more concise, too:
if x == nil
x = ...
end
This is a very common pattern. It can often be written as:
x ||= ...
This will assign the right-hand side to x if x is falsey, i.e. either nil or false.
In your example it becomes:
board[count] ||= Array.new(8)
The explicit counter variable can also be avoided by using Array#each_index. This shrinks your whole until block to:
board.each_index { |i| board[i] ||= Array.new(8) }
To get rid of the index, you could also use map!:
board.map! { |e| e || Array.new(8) }
This will replace each element e with the block's result, which is either just e or – if e is falsey – an array of 8 nils.
You can do it like
board[count] = [nil]*8
If you're looking to make a two-dimensional array of size n by m populated by value x:
Array.new(n) { Array.new(m, x) }
So in your case you can adapt your code to be:
Array.new(count) { Array.new(8) }
The default value in an array is nil.

Resources