Passing not as a variable - ruby

I have two functions, each of which pulls items from an array while asking if a certain value is present or not. How could I create a method that can be flipped according to whether I'm asking if the value is present or not? The (!) below is what I'd like to pass as a variable.
ary.select{ |item| (!)item.my_value.nil? }
Is it possible to pass not to as a variable, somewhat like multiplying something by x where x could be 1 or -1?

I'll assume this is in general terms and you are wondering how to pass something that you can use in the implementation of your function to reverse it. Two strategies:
Ruby metaprogramming. You can use the BasicObject#! and Object#itself:
<
def values_from(array, post_mutator:)
array.select { |item| item.nil?.public_send(post_mutator) }
end
array = [1, nil, :b, nil, nil, 'foo']
values_from(array, post_mutator: :itself) # => [nil, nil, nil]
values_from(array, post_mutator: :!) # => [1, :b, "foo"]
Boolean algebra. Basically, you want to find an operation ., for which:
x . true = x
x . false = -x
All possibilities are:
true, true => true
false, false => true
false, true => false
true, false => false
Which obviously leaves the . to be equality. Therefore:
def values_from(array, switcher)
array.select { |item| item.nil? == switcher }
end
array = [1, nil, :b, nil, nil, 'foo']
values_from(array, true) # => [nil, nil, nil]
values_from(array, false) # => [1, :b, "foo"]

ndn's answer addresses how to do this with Ruby meta-programming, but I was hoping for something a little more elegant, so I ended up addressing this by adding to TrueClass and FalseClass (with a RoR initializer).
class TrueClass
def *(value)
!!value
end
end
class FalseClass
def *(value)
!value
end
end
So I can do the following, which feels a bit more natural.
def select_from_ary(present)
ary.select{ |item| present * item.my_value.nil? }
end

If you have a function called presence? that returns true when you checking the item is present and false when you're checking it's absent then:
ary.select{ |item| !!item.my_value == presence? }
Or as a method where the Boolean is passed in:
def get_value_presence(boolean presence?)
ary.select{ |item| !!item.my_value == presence? }
end

Splitting the truesand falses - that is what partition does:
array = [1, nil, :b, nil, nil, 'foo']
nils, non_nils = array.partition{|item| item.nil?} # or: array.partition(&:nil?)

Related

Ruby hash: return the first key value under which is not nil

Say I have a hash
hash = {a:1, b:false, c:nil}
& a series of keys somewhere: [:c, :b, :a]. Is there a Ruby idiom for returning such a key value under which != nil?
The obv
[:c, :b, :a].select {|key| hash[key] != nil}.first # returns :b
seems too long.
For that I think Enumerable#find might work:
find(ifnone = nil) { |obj| block } → obj or nil
find(ifnone = nil) → an_enumerator
Passes each entry in enum to block. Returns the first for which block
is not false. If no object matches, calls ifnone and returns its
result when it is specified, or returns nil otherwise.
If no block is given, an enumerator is returned instead.
In your case it'd return the first for which block is not nil:
p %i[c b a].find { |key| !{ a: 1, b: nil, c: nil }[key].nil? } # :a
p %i[c b a].find { |key| !{ a: 1, b: 1, c: nil }[key].nil? } # :b
If you want to filter elements with falsy values, you can use the following expressions.
keys = [:d, :c, :b, :a]
hash = { a: 1, b: nil, c: nil, d: 2 }
keys.select(&hash)
# => [:d, :a]
If you want to filter elements with exactly nil as a value, it is not correct, as Mr. Ilya wrote.
You can use detect this will return first value if match.
[:c, :b, :a].detect { |key| hash[key] != nill }. This will return :b.
Hope to help you :D

Ruby Method not Returning False within a Recursion Block

I'm doing a ruby challenge that I found on rubeque.com. Here are the instructions:
Instructions:
Write a method #r_empty? that returns true if a hash and its subhashes are empty or false if there is a value in the hash.
My Answer:
class Hash
def r_empty?
def recurse(h)
h.each {|key, value|
value.is_a?(Hash) ? recurse(value) :
if (value!=nil && value!="")
#puts value
return false
end
}
return true
end
recurse(self)
end
end
Test:
a = {:ruby => "", :queue => ""}
b = {:ruby => {:version => {:one => {"nine" => ""}, "two" => "=^.^="}},
:html => ""}
c = {:pets => {:dogs => {:my => {"niko" => ""}, "ollie" => ""}}, :cats =>
nil, :mice => ""}
d = {a: "", b: :two, c: ""}
Answers:
a.r_empty?, true
b.r_empty?, false
c.r_empty?, true
d.r_empty?, false
({}.r_empty?), true
Using this code, I was able to get the right answer for 4 out of the 5 tests. My method returns TRUE for b.r_empty? ... I do notice that if I uncomment out #puts value, "=^.^=" is printed out for b.r_empty? ... So the if statement is being executed, but ultimately false is not returned. I'm still a ruby novice so I will gladly appreciate any advice and guidance towards the right topics i should go over for this challenge.
Although it's cool to define a method inside another (I did not know this was possibly actually) the method can be simplified quite a bit:
class Hash
def r_empty?
!values.any? do |val|
val.is_a?(Hash) ? !val.r_empty? : (val && val != "")
end
end
end
I'm not sure exactly the problem is with your original code, however I think the recurse(value) is effectively being discarded.
By the way, in terms of style I recommend only using a ternary for single-line expressions and also being diligent about consistent indentation.

Distinguish {k: :v} vs. [:k, :v] when iterating through Hash/Array

I need to implement the callback on #each. The receiver of each might be both Array and Hash. So, I have a code like:
receiver.each do |k, v|
case receiver
when Hash then puts "#{k} = #{v}"
when Array then puts "[#{k}, #{v}]"
end
end
The check for receiver is lame, though. Is there a way to receive/interprete a codeblock argument[s] to clearly distinguish the following cases:
{ a: 1, b: 2 }
versus
[[:a, 1], [:b, 2]]
I tried parenthesis, single argument, splatted argument. Everything just gets an Array of size 2. Am I doomed to stick with explicit type check?
The best you can do is to get the type check out of the loop:
def foo(receiver)
format = receiver.is_a?(Array) ? "[%s, %s]" : "%s = %s"
receiver.each do |k_v|
puts format % k_v
end
end
See String#%
If you want to tell, within the each block, whether the key/value pair came from an array or a hash, you have to resort to monkey patching. It can be done, but it's pretty awful:
class Hash
orig_each = instance_method(:each)
define_method(:each) do |&block|
orig_each.bind(self).call do |kv|
def kv.from_hash?
true
end
def kv.from_array?
false
end
block.call(kv)
end
end
end
class Array
orig_each = instance_method(:each)
define_method(:each) do |&block|
orig_each.bind(self).call do |kv|
def kv.from_hash?
false
end
def kv.from_array?
true
end
block.call(kv)
end
end
end
in use:
e = {a: 1, b: 2}
e.each do |kv|
p [kv.from_hash?, kv.from_array?, kv]
end
# => [true, false, [:a, 1]]
# => [true, false, [:b, 2]]
e = [[:a, 1], [:b, 2]]
e.each do |kv|
p [kv.from_hash?, kv.from_array?, kv]
end
# => [false, true, [:a, 1]]
# => [false, true, [:b, 2]]

Whether one of the elements of an array or a hash is nil

Is there any method that tells that one of the elements of an array or a hash is nil?
For an array
array = [1, 2, 'a']
array.any?(&:nil?)
#=> false
For a hash, I guess you are talking about nil values.
hash = {:a => 1, :b => 2, :c => nil}
hash.value?(nil)
#=> true
You can use the any? method: http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-any-3F
For example:arr.any? { |x| x.nil? }
As oldergod and strmstn have pointed out you should use any, and in the condition inside block you can verify whether an element is a nil or its class is Hash
[1,2,nil].any? {|x| x.class == Hash or x.nil? } # => true
[1,2,{}].any? {|x| x.class == Hash or x.nil? } # => true

Searching for range overlaps in Ruby hashes

Say you have the following Ruby hash,
hash = {:a => [[1, 100..300],
[2, 200..300]],
:b => [[1, 100..300],
[2, 301..400]]
}
and the following functions,
def overlaps?(range, range2)
range.include?(range2.begin) || range2.include?(range.begin)
end
def any_overlaps?(ranges)
# This calls to_proc on the symbol object; it's syntactically equivalent to
# ranges.sort_by {|r| r.begin}
ranges.sort_by(&:begin).each_cons(2).any? do |r1, r2|
overlaps?(r1, r2)
end
end
and it's your desire to, for each key in hash, test whether any range overlaps with any other. In hash above, I would expect hash[:a] to make me mad and hash[:b] to not.
How is this best implemented syntactically?
hash.each{|k, v| puts "#{k} #{any_overlaps?( v.map( &:last )) ? 'overlaps' : 'is ok'}."}
output:
a overlaps.
b is ok.
Here's another way to write any_overlaps:
def any_overlaps?(ranges)
(a = ranges.map { |r| [r.first, r.last] }.sort_by(&:first).flatten) != a.sort
end
any_overlaps? [(51..60),(11..20),(18..30),(0..10),(31..40)] # => true
any_overlaps? [(51..60),(11..20),(21..30),(0..10),(31..40)] # => false

Resources