Conditional Boolean If statement syntax in ruby - 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']]

Related

hash.key(my_key) not accessing keys in nested hash in ruby

1- I have little experience in ruby and I am coming from C/Python.
2- In the following snippet:
CSV.foreach(filename, quote_char: '"', col_sep: "\t") do |row|
if header_seen == true
k = row[primer]
c = row[counts].to_i
p = row[prfreq].to_f
e = row[err].to_f
print k," ",table.keys," ",table,"\n"
if table.key(k) == true
table[k]['counts'] << c
table[k]['err'] << e
table[k]['prfreq'] << p
else
puts "WHY IT IS ALWAYS GETTING HERE???"
table[k] = {'counts'=>[c],
'err'=>[e],
'prfreq' => [p]
}
end
elsif header_seen == false and row[0] == "BARCODE"
counts = row.index('PRCOUNT')
primer = row.index('PRIMER')
prfreq = row.index('PRFREQ')
err = row.index('ERROR')
header_seen = true
end
end
Printing table.keys (line 8), I can see the keys. However, if table.key(k) == true never comes true.
What am I doing wrong?
Assuming that table is a Hash (which we don't know for sure from your code), table.key(k) returns the value for the key k, if the key exists in your hash, or nil if it does not. Since the values of your Hash are seemingly not boolean values, the comparision with true will always be false.
If you just want to test, whether the key exists, use the method key? instead of key:
if table.key?(k)
...
end
(explicit comparision with true could be done in this case, but is redundant, so I left it out).
If your Hash has been constructed to use the standard value for it's default value (i.e. nil), you can shorten this to
if table[k]
...
end
The main difference between table.key(k) and table[k] is that if k is missing in the Hash, the former always returns nil, while the latter returns the default value for this particular Hash which you provided in the constructor.
See here for details.
It should be table.key?(k) instead of table.key(k)

Check whether string match or not

I have a string and an array with some strings.
as below
hostname = TETDC3DBE01
Array = ['WEB','APP','STR','DBE']
I want to find whether that hostname match with any of the array element or not?
When I'm trying with below code getting output
no
no
no
no
Here is loop repeating each and every element on array. I want check that hostname with single check on array the produce the output either yes or no only.
Array.each do |x|
if hostname.match(x)
puts "yes"
else
puts "no"
end
end
Given this fixed Ruby code:
hostname = 'TETDC3DBE01'
array = ['WEB','APP','STR','DBE']
Where if you want to find all elements in array that match as a substring of hostname your code should work. The more minimal matching system is probably:
array.select { |x| hostname.match(x) }
# => ["DBE"]
Using a tool like puts to produce output isn't always very useful because that "yes" or "no" text can't be acted upon by more code. Try and think of Ruby programs as a chain of transformations, where this selects all matches, and later you can print them, like this:
puts array.select { |x| hostname.match(x) }.join(',')
# => DBE
Check out Array#any? method.
It passes each element of the collection to the given block. The method returns true if the block ever returns a value other than false or nil. If the block is not given, Ruby adds an implicit block of { |obj| obj } that will cause any? to return true if at least one of the collection members is not false or nil.
If instead a pattern is supplied, the method returns whether pattern === element for any collection member.
In your case:
hostname = 'TETDC3DBE01'
['WEB','APP','STR','DBE'].any? do |x|
hostname.match(x)
end
or even if you actually mean equal by match:
hostname = 'TETDC3DBE01'
['WEB','APP','STR','DBE'].any?(hostname)
Lets take your code to fix it.
hostname = "TETDC3DBE01"
arr = ['WEB','APP','STR','DBE']
arr.each do |x|
if hostname.match?(x)
puts "yes"
else
puts "no"
end
end
match gives array of result and
match? gives you true or false value
I wouldn't use regexp in this case. A simple String#include? is probably faster. Furthermore any? will return true if any of the elements in the array leads is matching.
hostname = 'TETDC3DBE01'
array = ['WEB','APP','STR','DBE']
array.any? { |x| hostname.include?(x) }
#=> true
Regular expression made real easy:
hostname = "TETDC3DBE01"
array = ['WEB','APP','STR','DBE']
re = Regexp.union(array)
hostname.match?(re) # => true

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

Why is this ruby test failing?

I am doing some of the kata challenges on codewars:
This is the challenge: An isogram is a word that has no repeating letters, consecutive or non-consecutive. Implement a function that determines whether a string that contains only letters is an isogram. Assume the empty string is an isogram. Ignore letter case.
I have the following piece of code:
def is_isogram(string)
string.downcase!
('a'..'z').each do |letter|
return string.count(letter) <= 1 || string.length == 0 ? true : false
end
end
with the following tests:
Test.assert_equals(is_isogram("Dermatoglyphics"), true )
Test.assert_equals(is_isogram("isogram"), true )
Test.assert_equals(is_isogram("aba"), false, "same chars may not be adjacent" )
Test.assert_equals(is_isogram("moOse"), false, "same chars may not be same case" )
Test.assert_equals(is_isogram("isIsogram"), false )
Test.assert_equals(is_isogram(""), true, "an empty string is a valid isogram" )
My code fails on the fourth test. Could someone please shed some light on what I am doing wrong and how I can get the test to pass?
You are returning from the method at the end of the first iteration. Thus, your code has nothing to do with isogram. Your code will check whether the first character in the range (i.e., "a") is repeated or not.
The first two examples only have one "a", so they return true. The third has more than one "a", so it returns false. The fourth has no "a", so it returns true.
To get your code to work, change it to:
def is_isogram(string)
string.downcase!
('a'..'z').each do |letter|
return false if string.count(letter) > 1
end
return true
end
But a more Rubyish way to write it is:
def is_isogram(string)
string = string.downcase
('a'..'z').none?{|letter| string.count(letter) > 1}
end
try this
def is_isogram(string)
string.downcase.chars.uniq == string.downcase.chars
end

rubymonk "all elements in an array are Fixnum"?

http://rubymonk.com/learning/books/1/problems/148-array_of_fixnum
Ruby monk suggests:
def array_of_fixnums?(array)
array.all? { |x| x.is_a? Fixnum }
end
That is fine and all, however the following code works in irb 1.9.2 but fails when rubymonk passes an empty array:
def array_of_fixnums?(array)
result = false
array.each { |n|
if n.is_a? Fixnum
result = true
else
result = false
end }
result
end
here is the irb output:
1.9.2-p320 :001 > array_of_fixnums? []
=> false
and here is what rubymonk says about my solution:
returns 'true' for [1,2,3] ✔
returns 'false' for ['a',1,:b] ✔
returns 'true' for []
RSpec::Expectations::ExpectationNotMetError
expected false to be true
I'm wondering why this is so?
Update based on answers:
def array_of_fixnums?(array)
result = true
array.each { |n| return false unless n.is_a? Fixnum }
result
end
Your code has two problems:
The problem is phrased in a slightly vague manner. What they actually want is for you to return false if any of the elements are not Fixnums, and true otherwise — so an empty array should give true. If you look at your code, you'll see that result starts out false, so if the array is empty, it will return false even though the test thinks it should be true. You can solve this by starting out with true.
Your code actually just detects whether the last element of the array is a Fixnum. Let's take the array [1, "nope", 3]. It will first see 1 and set result to true, then it will see "nope" and set result to false, then it will see 3 and set result to true, and that's what the method will return. RubyMonks tests actually don't detect this error, but it would show up in the real world. You want to return immediately after getting a false result, as that is enough to determine that the array is not all Fixnums.
For this case you will never enter the each cycle as there are no elements in array. So you return the defualt value of result that you set to false on the line above. However if there are no elements in an array, then all of its elements are Fixnums and so you should return true.

Resources