def check_nill(array1)
p = Proc.new {array1.any? { |x| x.nil? }}
if p == true
puts "true"
else
puts "false"
end
end
it always give me false and i dont know why
Proc.new does not actually run the code. You have to pass it over, or call it using Proc#call.
is_nil = Proc.new {|item| item.nil?}
["a", "b", nil].any?(is_nil)
# => true
Your code always return false because p was an instance of Proc, and not the result of the block.
p = Proc.new {array1.any? { |x| x.nil? }} # <Proc:0x0000000>
if p == true # <Proc:0x0000000> == true? no
puts "true"
else
puts "false" # prints false
end
You are overdoing it, creating a proc inside a method and then not calling it.
check_nil = proc {|ar| ar.any?{|x| x.nil?} # or just proc {|ar| ar.any?(nil)}
puts check_nil.call([1,2,nil,3]) # => true
Is there an "easy" way, short of hand-writing the kind of nested Hash/Array traversal performed by Hash#dig, that I can determine if a key is present in a deeply nested Hash? Another way to ask this is to say "determine if any value is assigned".
There is a difference between a Hash having nothing assigned, or it having an explicit nil assigned - especially if the Hash were constructed with a different missing key default value than nil!
h = { :one => { :two => nil }}
h.dig(:one, :two).nil? # => true; but :two *is* present; it is assigned "nil".
h[:one].key?(:two) # => true, because the key exists
h = { :one => {}}
h.dig(:one, :two).nil? # => true; :two *is not* present; no value is assigned.
h[:one].key?(:two) # => FALSE, because the key does not exist
If you are purely checking the existence of a key, you can combine dig and key?. Use key? on the final or last key in your series of keys.
input_hash = {
hello: {
world: {
existing: nil,
}
}
}
# Used !! to make the result boolean
!!input_hash.dig(:hello, :world)&.key?(:existing) # => true
!!input_hash.dig(:hello, :world)&.key?(:not_existing) # => false
!!input_hash.dig(:hello, :universe)&.has_key?(:not_existing) # => false
Inspired by your core extension suggestion I updated the implementation a bit to better mimic that of #dig
requires 1+ arguments
raises TypeError if the dig does not return nil, the resulting object does not respond to dig? and there are additional arguments to be "dug"
module Diggable
def dig?(arg,*args)
return self.member?(arg) if args.empty?
if val = self[arg] and val.respond_to?(:dig?)
val.dig?(*args)
else
val.nil? ? false : raise(TypeError, "#{val.class} does not have a #dig? method")
end
end
end
[Hash,Struct,Array].each { |klass| klass.send(:include,Diggable) }
class Array
def dig?(arg,*args)
return arg.abs < self.size if args.empty?
super
end
end
if defined?(OpenStruct)
class OpenStruct
def dig?(arg,*args)
self.to_h.dig?(arg,*args)
end
end
end
Usage
Foo = Struct.new(:a)
hash = {:one=>1, :two=>[1, 2, 3], :three=>[{:one=>1, :two=>2}, "hello", Foo.new([1,2,3]), {:one=>{:two=>{:three=>3}}}]}
hash.dig? #=> ArgumentError
hash.dig?(:one) #=> true
hash.dig?(:two, 0) #=> true
hash.dig?(:none) #=> false
hash.dig?(:none, 0) #=> false
hash.dig?(:two, -1) #=> true
hash.dig?(:two, 10) #=> false
hash.dig?(:three, 0, :two) #=> true
hash.dig?(:three, 0, :none) #=> false
hash.dig?(:three, 2, :a) #=> true
hash.dig?(:three, 3, :one, :two, :three, :f) #=> TypeError
Example
For reference - taking the unusual step of answering my own question ;-) - here's one of several ways I could solve this if I just wanted to write lots of Ruby.
def dig?(obj, *args)
arg = args.shift()
return case obj
when Array
if args.empty?
arg >= 0 && arg <= obj.size
else
dig?(obj[arg], *args)
end
when Hash
if args.empty?
obj.key?(arg)
else
dig?(obj[arg], *args)
end
when nil
false
else
raise ArgumentError
end
end
Of course, one could also have opened up classes like Array and Hash and added #dig? to those, if you prefer core extensions over explicit methods:
class Hash
def dig?(*args)
arg = args.shift()
if args.empty?
self.key?(arg)
else
self[arg]&.dig?(*args) || false
end
end
end
class Array
def dig?(*args)
arg = args.shift()
if args.empty?
arg >= 0 && arg <= self.size
else
self[arg]&.dig?(*args) || false
end
end
end
...which would raise NoMethodError rather than ArgumentError if the #dig? arguments led to a non-Hash/Array node.
Obviously it would be possible to compress those down into more cunning / elegant solutions that use fewer lines, but the above has the benefit of IMHO being pretty easy to read.
In the scope of the original question, though, the hope was to lean more on anything Ruby has out-of-the-box. We've collectively acknowledged early-on that there is no single-method solution, but the answer from #AmazingRein gets close by reusing #dig to avoid recursion. We might adapt that as follows:
def dig?(obj, *args)
last_arg = args.pop()
obj = obj.dig(*args) unless args.empty?
return case obj
when Array
last_arg >= 0 && last_arg <= obj.size
when Hash
obj.key?(last_arg)
when nil
false
else
raise ArgumentError
end
end
...which isn't too bad, all things considered.
# Example test...
hash = {:one=>1, :two=>[1, 2, 3], :three=>[{:one=>1, :two=>2}, "hello", {:one=>{:two=>{:three=>3}}}]}
puts dig?(hash, :one)
puts dig?(hash, :two, 0)
puts dig?(hash, :none)
puts dig?(hash, :none, 0)
puts dig?(hash, :two, -1)
puts dig?(hash, :two, 10)
puts dig?(hash, :three, 0, :two)
puts dig?(hash, :three, 0, :none)
puts dig?(hash, :three, 2, :one, :two, :three)
puts dig?(hash, :three, 2, :one, :two, :none)
Here is a concise way of doing it which works with nested Array and Hash (and any other object that responds to fetch).
def deep_fetch? obj, *argv
argv.each do |arg|
return false unless obj.respond_to? :fetch
obj = obj.fetch(arg) { return false }
end
true
end
obj = { hello: [ nil, { world: nil } ] }
deep_fetch? obj, :hell # => false
deep_fetch? obj, :hello, 0 # => true
deep_fetch? obj, :hello, 2 # => false
deep_fetch? obj, :hello, 0, :world # => false
deep_fetch? obj, :hello, 1, :world # => true
deep_fetch? obj, :hello, :world
TypeError (no implicit conversion of Symbol into Integer)
The previous code raises an error when accessing an Array element with a non-Integer index (just like Array#dig), which sometimes is not the behavior one is looking for. The following code works well in all cases, but the rescue is not a good practice:
def deep_fetch? obj, *argv
argv.each { |arg| obj = obj.fetch(arg) } and true rescue false
end
obj = { hello: [ nil, { world: nil } ] }
deep_fetch? obj, :hell # => false
deep_fetch? obj, :hello, 0 # => true
deep_fetch? obj, :hello, 2 # => false
deep_fetch? obj, :hello, 0, :world # => false
deep_fetch? obj, :hello, 1, :world # => true
deep_fetch? obj, :hello, :world # => false
This question already has answers here:
How to see if the characters of one string appear in order in a second string
(4 answers)
Closed 2 years ago.
Given two strings, word and key, how can I write a method sequence_search(word, key) that returns true (else false) if the characters in key appear in the same order (but not necessarily contiguous) in word?
def sequence_search(word, key)
new = key.chars
arr = []
i = 0
while i < word.length
if word[i].include?(key)
arr >> word[i]
end
i+= 1
end
if arr.join == key # line raising exception
return true
end
return false
end
end
sequence_search("arcata", "cat") #=> true
sequence_search("c1a2t3", "cat") #=> true
sequence_search("cta", "cat") #=> false
sequence_search("coat", "cat") #=> true
You could use Enumerable#all? which returns true if its block never returns false or nil:
def sequence_search(word, keys)
idx = -1
keys.chars.all? do |c|
idx = word.index(c) if word.index(c) && word.index(c) > idx
end
end
sequence_search("arcata", "cat") #=> false
sequence_search("c1a2t3", "cat") #=> true
sequence_search("cta", "cat") #=> false
sequence_search("coat", "cat") #=> true
You can solve this with regex:
def sequence_search(word, key)
word =~ Regexp.new(key.chars.join('.*')) ? true : false
end
p sequence_search("arcata", "cat")
p sequence_search("c1a2t3", "cat")
p sequence_search("cta", "cat")
p sequence_search("coat", "cat")
# true
# true
# false
# true
I am trying to recreate the enumerable module in Ruby. I am up to the any? method and having difficulty returning true or false. Instead each array item is returned 1 by 1.. Here is my code:
def my_any?
return self.to enum unless block_given?
self.each do |i|
return true if i == yield(i)
end
end
nums = [3,5,7,3,6,10,20,16]
puts nums.my_any?{|x|x==6}
Any ideas where I am going wrong?
You have three issues with your code: you should return an enumerator for this method when called without block, you should check just what yield returns, and you should explicitly return false on fail:
def my_any?
return to_enum(:my_any?) unless block_given?
each { |i| return true if yield(i) }
false
end
nums = [3,5,7,3,6,10,20,16]
puts nums.my_any? { |x| x == 6 }
#⇒ true
lazy = nums.my_any?
lazy.each { |x| x == 6 }
#⇒ true
Or, I would better use break:
def my_any?
return to_enum(:my_any?) unless block_given?
each { |i| break true if yield(i) } == true
end
You have two issues:
You're missing a return false if the loop fails to find a match. Currently when it fails to match, it'll give the return value from each, which is what you're seeing.
It's currently always failing, because while your return true if cond construct is right, any?'s conditional is not i == yield(i): you've got too many comparisons. You need just yield(i).
(The to enum bit sounds off too, but that's unrelated to your question.)
Slotting those changes into your code:
def my_any?
# FIXME: return self.to enum unless block_given?
self.each do |i|
return true if yield i
end
false
end
"0".to_i == 0
also:
"abcdefg".to_i == 0
I want to make sure the string I'm parsing really is just a number (0 included).
Integer("0").zero? rescue false
# => true
Integer("1").zero? rescue false
# => false
Integer("abcdefg").zero? rescue false
# => false
def string_is_integer?(string)
!string.match(/^(\d)+$/).nil? # \d looks for digits
end
def string_is_float?(string)
!string.match(/^(\d)+\.(\d)+$/).nil?
end
def string_is_number?(string)
string_is_integer?(string) || string_is_float?(string)
end
Or, if you don't mind:
def string_is_number?(string)
begin
true if Float(string)
rescue ArgumentError
end || false
end
def is_zero?(string)
(Integer(string) rescue 1).zero?
end
is_zero? "0" #=> true
is_zero? "00000" #=> true
is_zero? "0cat" #=> false
is_zero? "1" #=> false
is_zero? "-0" #=> true
is_zero? "0_000" #=> true
is_zero? "0x00" #=> true
is_zero? "0b00000000" #=> true
Several of these examples illustrate why it's preferable to use Kernel#Integer rather than a regular expression.
First test if the string is integer or not and then match
def is_i?(x)
!!(x =~ /\A[-+]?[0-9]+\z/)
end
def is_zero?(x)
return is_i?(x) && x.to_i == 0
end
# is_zero?("0") will return true
# is_zero?("abcde") will return false
Or you can put these methods in String class like this
class String
def is_i?
!!(self =~ /\A[-+]?[0-9]+\z/)
end
def is_zero?
self.is_i? && self.to_i == 0
end
end
"0".is_zero? # true
"abcde".is_zero? # false
I want to make sure the string I'm parsing really is just a number.
There are two steps involved:
Parsing, i.e. converting the string into a number
Validation, i.e. checking if the string actually is a number
The built-in conversion functions like Integer and Float already perform both steps: they return a numeric result if the string is valid and raise an error otherwise.
Using these functions just for validation and discarding the return value is wasteful. Instead, use the return value and handle the exception, e.g.:
begin
puts 'Enter a number:'
number = Float(gets)
rescue
puts 'Not a valid number'
retry
end
# do something with number
or something like:
def parse_number(string)
Float(string) rescue nil
end
number = parse_number(some_string)
if number
# do something with number
else
# not a number
end