Seeing if values of a hash are the same - ruby

I have a hash, whose values are true or false. What is the most Ruby-esque way to see if all the values of a given sub-hash of this hash are the same?
h[:a] = true
h[:b] = true
h[:c] = true
h[:d] = false
[h[:a], h[:b], h[:c]].include? false
[h[:a], h[:b], h[:c]].include? true
Is there a better way to write this?

values_at is the method to get a collection of values out of a Hash:
h.values_at(:a,:b,:c).all? #are they all true?
h.values_at(:a,:b,:c).any? #is at least one of them true?
h.values_at(:a,:b,:c).none? #are they all false?

If all you want to do is evaluate they are ALL true or they are ALL false:
h[:a] && h[:b] && h[:c] && h[:d] # => false
!(h[:a] || h[:b] || h[:c] || h[:d]) # => false
h[:a] && h[:b] && h[:c] # => true
!h[:d] # => true
Otherwise, as Dave Newton pointed out, you can use the #all?, #any? and #none? methods.

> [h[:a], h[:b], h[:c]].all?
=> true
> [h[:a], h[:b], h[:d]].all?
=> false
> [h[:a], h[:b], h[:d]].all?
=> false
> [h[:d]].none?
=> true
all?, none?
Depending on your needs it might be cleaner to write something like:
> [:a, :b, :c].all? { |key| h[key] }
=> true
> [:a, :b, :d].all? { |key| h[key] }
=> false
> [:a, :d].none? { |key| h[key] }
=> false
> [:d].none? { |key| h[key] }
=> true

Another general-purpose method:
whatever.uniq.size == 1
This tests directly whether all the values in whatever are the same. So, in your case,
h.values_at(:a, :b, :c).uniq.size == 1

Related

Check if multiple key-value pairs exist in a Ruby hash?

I have the following Ruby hash key-value pairs:
[
{
"trait_type"=>"Status",
"value"=>"Unbuilt",
"display_type"=>nil,
"max_value"=>nil,
"trait_count"=>4866,
"order"=>nil
}
]
What I need to check is see if the following key-value pairs are both present:
{
"value"=>"Unbuilt",
"trait_type"=>"Status"
}
Essentially wanting something to the effect of...
traits = [{"trait_type"=>"Status", "value"=>"Unbuilt", "display_type"=>nil, "max_value"=>nil, "trait_count"=>4866, "order"=>nil}]
filter_traits = {"value"=>"Unbuilt", "trait_type"=>"Status"}
traits.include? filter_traits
If you are using ruby >= 2.3, there is a fancy new Hash >= Hash operation that is conceptually similiar to a hypothetical contains?
Using your traits array:
trait = traits[0]
trait >= {"trait_type" => "Status", "value" => "Unbuilt"}
# => true
trait >= {"trait_type" => "Status", "value" => "Built"}
# => false
So you could try something like:
traits.select{|trait|
trait >= filter_traits
}.length > 0
# => true
arr = [
{
"trait_type"=>"Status",
"value"=>"Unbuilt",
"display_type"=>nil,
"max_value"=>nil,
"trait_count"=>4866,
"order"=>nil
}
]
h1 = { "value"=>"Unbuilt", "trait_type"=>"Status" }
h2 = { "value"=>"Rebuilt", "trait_type"=>"Status" }
Here are three solutions.
arr[0].slice(*h1.keys) == h1
#=> true
arr[0].slice(*h2.keys) == h2
#=> false
arr[0].values_at(h1.keys) == h1.values
#=> true
arr[0].values_at(h2.keys) == h2.values
#=> false
arr[0] == arr[0].merge(h1)
#=> true
arr[0] == arr[0].merge(h2)
#=> false
We also have the aptly named all? and any? methods that should do exactly what you're looking for in a very logical way.
All we need to do is loop through your filter_traits hash and test to see if all (or any) those key:value pairs are equal to (==) any corresponding key:value pairs inside your traits array:
traits = [{"trait_type"=>"Status", "value"=>"Unbuilt", "display_type"=>nil, "max_value"=>nil, "trait_count"=>4866, "order"=>nil}]
filter_traits = {"value"=>"Unbuilt", "trait_type"=>"Status"}
filter_traits.all? {|k, v| filter_traits[k] == traits[0][k]}
#=> true
filter_traits = {"value"=>"Built", "trait_type"=>"Status"}
filter_traits.all? {|k, v| filter_traits[k] == traits[0][k]}
#=> false
filter_traits.any? {|k, v| filter_traits[k] == traits[0][k]}
#=> true

Check if a string contains only digits in ruby

I have a string which is passed as a parameter to a function. Here, I want to check if the string contains only numbers. So I had a check like below:
def check_string(string)
result = false
if string.to_i.to_s.eql? string
result = true
end
result
end
But the problem arises when a string starts with 0. In that case, a false is returned.
check_string('123') #=> true
check_string('0123') #=> false
How can I solve this issue?
You can try the following
def check_string(string)
string.scan(/\D/).empty?
end
It would be truthy if string contains only digits or if it is an empty string. Otherwise returns false.
A number can be negative, or a float. So if these are allowed, consider this solution:
def is_numberic?(str)
str == "#{str.to_f}" || str == "#{str.to_i}"
end
some input which evaluate to true
pry(main)> is_numberic? '5'
=> true
pry(main)> is_numberic? '58127721'
=> true
pry(main)> is_numberic? '58127721.737673'
=> true
pry(main)> is_numberic? '0'
=> true
pry(main)> is_numberic? '1818'
=> true
pry(main)> is_numberic? '0.1'
=> true
pry(main)> is_numberic? '0.0'
=> true
pry(main)> is_numberic? '11.29'
=> true
pry(main)> is_numberic? '-0.12'
=> true
pry(main)> is_numberic? '-29'
=> true
the input which evaluate to false
pry(main)> is_numberic? '10 years'
=> false
pry(main)> is_numberic? '01'
=> false
pry(main)> is_numberic? '00'
=> false
pry(main)> is_numberic? '0.10'
=> false
pry(main)> is_numberic? ''
=> false
As you can see, there're several cases which probably should be supported, eg '0.10', but are not. In this case, the permitted input is '0.1'.
def check_string(str)
str !~ /\D/
end
check_string '123'
#=> true
check_string ''
#=> true
check_string '1a2'
#=> false
this is my proposition for detecting if it's a float number
def check(string)
scan = string.scan(/\D/)
scan.size == 0 || (scan.size == 1 && scan.first == ".") # or "," depend on your separator
end
example of use:
check("123") => true
check("12.3") => true
check("12e3") => false
check("12.3.2") => false
EDIT: 2023
After some years i see this is the most compact solution:
def check_string(str)
str.scan(/\D/).empty?
end
You can use Regexp for it:
def check_string(string)
raise 'Empty string passed' if string.empty?
/\A\d+\z/ === string
end
check_string '123'
#=> true
check_string '0123'
#=> true
check_string '0'
#=> true
We can also use the "match" function to do this.
"1234".match(/\D/)
#=> nil
"1234foo".match(/\D/)
#=> #<MatchData "f">
match (String) - APIdock
I think we should use the regex to find this.
it will work for the below scenarios
"3.0"
"av3"
"3"
is_numeric = false if option.option.match?(/[^0-9.]/)
If anyone is searching for another way to determine if string is numeric -> is to use "is_a? Numeric". Is_a? reference documentation
"namaste".is_a? Numeric
=> false
6.is_a? Numeric
=> true
str1 = "foo"
str2 = 9
str1.is_a? Numeric
=> false
str2.is_a? Numeric
=> true
You can also use:
7.is_a?(Numeric)
=> true
"too".is_a?(Numeric)
=> false
Basically it's determining if a class is a type of class object. I just found this and thought I would share.

Passing not as a variable

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

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

How do you perform boolean operations over all elements of an array and mix the result together?

I want to AND or OR all the elements in an array, but with some control, as shown via the hash element selection. Here is the behavior that I wish to achieve:
a = [{:a => true}­, {:a => false­}]
a.and_map{ |hash_element| hash_element[:a] }
#=> false
a.or_map{ |hash_element| hash_element[:a] }
#=> true
Is there a slick, clean way to do this in Ruby?
You can use all? and any? for that:
a = [{:a => true}, {:a => false }]
a.any? { |hash_element| hash_element[:a] }
#=> true
a.all? { |hash_element| hash_element[:a] }
#=> false
a = [{:a => true}­, {:a => false­}]
a.all?{ |elem| elem[:a] }
a.any?{ |elem| elem[:a] }

Resources