How best to loop through multiple functions in Ruby? - ruby

Is there a more concise way to loop through a number of conditions than this?
def is_this_whole_thing_true?
result = false
result = true if condition_1?
result = true if condition_2?
result = true if condition_3?
result = true if condition_4?
result = true if condition_5?
result = true if condition_6?
result = true if condition_7?
result
end
Thanks for any help.

If you don't care to create a whole array I think this is the best option
def is_this_whole_thing_true?
conditions = [condition1?, condition2?, condition3?, condition4?]
conditions.any?
end

you can simply put && condition here like:
def is_this_whole_thing_true?
condition_1? && condition_2? && condition_3? && ...
end
Infact, what you are trying to do in the method is return true if any of the condition is true, then use ||
def is_this_whole_thing_true?
condition_1? || condition_2? || condition_3? || ...
end
An advantage of this is, it won't check all of the conditions, as soon as any one of the condition turns out to be true, it will return.

Related

simple ruby unless method mistake

I am very new to ruby. This might sound very naive to you but I can't understand what is happening here
matched_criteria = match_criteria(c1, c2)
puts "answer is #{matched_criteria}"
def match_criteria(crit_val1, crit_val2)
if crit_val1.present?
puts "present"
else
puts "absent"
end
return true unless crit_val1.present? || crit_val2.present?
return false unless crit_val1.present? && crit_val2.present?
end
Output:
absent
answer is false
please explain
def match_criteria(crit_val1, crit_val2)
# Check if #1 is present? or blank?
if crit_val1.present?
puts "present"
else
puts "absent"
end
# Return true unless EITHER (||) are present
# ...or you could think of it like...
# Return true if BOTH (&&) are blank
return true unless crit_val1.present? || crit_val2.present?
# Return false unless BOTH are present
# ..or...
# Return false if EITHER is blank
return false unless crit_val1.present? && crit_val2.present?
end
This is actually a Ruby on Rails question. blank? and present? are instance methods only available in Rails, but not in the standard Ruby library.
Whenever you call match_criteria with one parameter that is a non-blank value, the condition
crit_val1.present? || crit_val2.present?
will be true, but since you are negating it the first return statement does not get called.
In that same situation the second conditional evaluates to false, and since you're negating it the second return successfully returns false.
Your problem has nothing to do with Ruby (or Rails) per se. It has to do with misunderstanding the logical operators involved, which of course would be a problem in any language.
Consider this:
def test(x, y)
return true unless x || y
false unless x && y
end
p test(true, false) # => false
p test(true, true) # => nil
p test(false, false) # => true
In the first test (x = true, y = false) the first condition fails because x || y is true (it would succeed only if x || y evaluated to false, since you're using unless instead of if). The second condition succeeds because x && y is not true. So, the method returns false.
In the second test, neither condition succeeds, because both x || y and x && y evaluate to true. (Again, since you are using unless instead of if, a condition can only succeed if it evaluates to false.) So, the method returns nil.
In the third test, the first condition succeeds, because x || y evaluates to false. So, the method returns false.
It's most unlikely that you want these logical conditions. In the first place, you probably don't want a set of logical conditions that doesn't cover all the possibilities. Also, I don't see a reason for using unless instead of if; it seems like you're needlessly complicating your logic.
Of course, you haven't explained exactly what logical conditions you're looking for, so we're all playing "blind mechanic" here to some extent. But my feeling is that you are attempting to check whether your crit_val1 or crit_val2 are present, and return false if either of them is. If so, all you would have to do is this:
def match_criteria(crit_val1, crit_val2)
# other stuff
return false if crit_val1.present? || crit_val2.present?
true
end

Conditional Boolean If statement syntax in ruby

I want the push elements of an API into my array if the condition for an attribute is true. So k_api_hash['awsaccounts'][i]['sandman'] will return true or false and, if the condition is true, I want to push the account number in to an array; (k_api_hash['awsaccounts'][i]['accountnumber']) will return an account number.
Code:
k_api_hash = JSON.parse(kens_api)
aws_account_size = k_api_hash["awsaccounts"].size
aws_account_array = []
i = 0
while i < aws_account_size
if k_api_hash['awsaccounts'][i]['sandman'] == "true"
aws_account_array.push(k_api_hash['awsaccounts'][i]['accountnumber'])
i += 1
else
i += 1
end
end
puts "Here are all the aws accounts"
puts aws_account_array.inspect
The problem is that it is returning null value, but successfully pushes the account numbers into the array if the if condition is taken out.
Output:
Here are all the aws accounts
[]
The if is returning false every time because you are comparing "true" (String) with true (TrueClass) / false (FalseClass); consider the following code:
true == "true"
#=> false
false == "true"
#=> false
true != "true"
#=> true
To make it work simply remove == "true"1 from your if:
if k_api_hash['awsaccounts'][i]['sandman']
1 Remember that any expression in an if that returns true/false (or a truthy/falsey value for that matter) needs no further comparison.
Not related to the error, but your code could be optimized by using a different iterator and removing unnecessary variables; for example, the following code will yield the same output:
k_api_hash = JSON.parse(kens_api)
aws_account_array = k_api_hash["awsaccounts"].each_with_object([]) do |account, r|
r << aws_account_array.push(account['accountnumber']) if account['sandman']
end
To understand better what is going on, take a look at Enumerable#each_with_object.
I think this would do the job:
k_api_hash = JSON.parse(kens_api)
awsaccounts = k_api_hash['awsaccounts']
aws_account_array = awsaccounts.reduce([]) { |array, acc|
array << acc['accountnumber'] if acc['sandman']
array
}
If the API is returning string booleans like "true" or "false" you could do a hash like:
bools = {true=>true, 'true'=>true}
and call it using what api returns as key inside the reduce
array << acc['accountnumber'] if bools[acc['sandman']]

Function to determine if a number is repeated in a year is true or false, seems to not like the 1800's?

I'm trying to write a function whether a number repeats, it seems like the function works most of the time but not reliably. I'm not sure what the problem with my code is, code follows:
def repeat?(year)
y_arr = year.to_s.split('').map(&:to_i)
y_arr.each do |i|
y_arr.each do |j|
if (i != j) && (y_arr[i] == y_arr[j])
return true
end
end
end
return false
end
puts(repeat?(1702))
puts(repeat?(1997))
puts(repeat?(2001))
puts(repeat?(1859))
output for the above ->
false
true
true
true (should be false?)
changed code to:
def repeat?(year)
y_arr = year.to_s.split('').map(&:to_i)
for i in 0..y_arr.length
for j in 0..y_arr.length
if (i != j) && (y_arr[i] == y_arr[j])
return true
end
end
end
return false
end
Works now! Thanks for your responses
You're making it much more complex than it needs to be. This can be done with a one-liner.
/(\d)\1+/ =~ number.to_s
The \1+ is known as a backreference in regex. It references what is captured between the parentheses which in this case is a digit.
This will find repeated digits.
It can also be done by checking whether digits are unique or not.
def repeat?(year)
not (year.to_s.chars == year.to_s.chars.uniq)
end
puts(repeat?(1702))
#=> false
puts(repeat?(1997))
#=> true
puts(repeat?(2001))
#=> true
puts(repeat?(1800))
#=> true

Refactoring method with multiple Logical ANDs

I have a method where I am regularly performing Logical AND on a variable, can it be refactored? This is sort of a 2 part question.
Is there a short circuit way of doing var = var && condition?
Is there a better way to write this based on multiple conditions and still only return a single boolean?
I'm hoping for something similar to a += kind of thing.
def my_method
var = true
if condition
var = var && cond1
end
if other_condition
var = var && cond2
end
var
end
I would use statement modifiers:
def my_method
res = true
res &&= cond1 if condition
res &&= cond2 if other_condition
res
end
Is there a short circuit way of doing var = var && condition?
Yes.
var &&= condition
Is there a better way to write this based on multiple conditions and still only return a single boolean?
def my_method
(cond1 || !condition ) &&
(cond2 || !other_condition)
end
Edit. p11y's comment is right.
If you don't like it, you can also write like this using keywords:
def my_method
(cond1 if condition ) and
(cond2 if other_condition)
end

Ruby method with few or zero parameters - how to do it?

I have two methods in Ruby:
def reverse(first,second)
#items[first..second]=#items[first..second].reverse
end
And:
def reverse
#items.reverse!
end
Can I combine these into one function and use an if first.nil? && second.nil? condition, or it is better to keep it like it is?
First option is to use default valued parameters:
def reverse(first = nil, second = nil)
if first && second
#items[first..second]=#items[first..second].reverse
else
#items.reverse!
end
end
The second option is to use variable number of args:
def reverse(*args)
if args.length == 2
#items[args.first..args.last]=#items[args.first..args.last].reverse
else
#items.reverse!
end
end

Resources