Check whether string match or not - ruby

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

Related

Not understanding the Boolean Logic to my method

I write the method capitalized(word) to be funneled into the .each function.
i use bang! to make the function work correctly but i don't understand why its working correctly.
The part that is really throwing me off is the !capitalized word line if statement. I don't understand the logic and how the method returns the answers that it does.
!false returns false in the method... why? And !true it returns true.
Whats the best way to understand this concept.
I have tried taking out the bang and putting it back in to see its effect.
And it just confuses me. Thank you for your help.
# A name is valid is if satisfies all of the following:
# - contains at least a first name and last name, separated by spaces
# - each part of the name should be capitalized
#
# Hint: use str.upcase or str.downcase
# "a".upcase # => "A"
def is_valid_name(str)
name = str.split(' ')
if name.length < 2
return false
end
name.each do |word|
if !capitalized(word)
return false
end
end
return true
end
def capitalized(word)
if word[0] == word[0].upcase && word[1..-1]== word[1..-1].downcase
return true
else
return false
end
end
puts is_valid_name("Kush Patel") # => true
puts is_valid_name("Daniel") # => false
puts is_valid_name("Robert Downey Jr") # => true
puts is_valid_name("ROBERT DOWNEY JR") # => false
The purpose of the part of the code you struggling with, is to check whether all of the elements of the name are capitalised. There are two ways you can approach that problem:
Find any element that is not capitalised.
If such element exists, that means name is not valid, so method is_valid_name should return false. This is the approach used in you code:
def is_valid_name(str)
#...
name.each do |word| #1
if !capitalized(word) #2
return false #3
end
end
return true #4
end
Iterate over every part of the name
Check if word is capitalized. We want to break only when we find invalid (not capitalized) word. That occurs when capitalized(word) returns false: so condition if !capitalized(word) is actually if !false, which is equal to if true.
We entered, that means our word is not valid, so we return false from is_valid_name method.
Check if all elements are capitalized
This is more straightforward solution. We just want to check, if method capitalized(word) returns true for all of the elements of the name.
To achieve that, we can use method all?, which returns true if condition in the block returns true for every element; otherwise false. So we can replace all the code above with single line:
name.all?{|word| capitalized(word) }
Final implementation of the validation method can look like that:
def is_valid_name(str)
name = str.split(' ')
name.length < 2 && name.all?{|word| capitalized(word)}
end
Hope it helps you!
!false returns false in the method... why?
I'm assuming you mean this one:
if !capitalized(word)
return false
end
"If capitalize returns false, why do we return false", this question? Because if a word is not capitalized, the name is invalid. That's the given business logic.

Why does Ruby require or operators for find_all method when searching multiple things?

Given the following code:
Why does Ruby require the or operator when searching for multiple things using the find_all method? I.e.:
x = [1,2,3,4,5]
variable = x.find_all do |x|
x.even?||x.odd?
end
puts variable
I am trying figure out whether each number within the array is either even or odd. At the end, eventually putting the result of variable, if it is either of those two.
If you try to write the conditions you want find sequentially, it does not work:
variable = x.find_all do |x|
x.even?
x.odd?
end
I am curious to know why that the first example works and the second one does not. The second equation, in my head I'm thinking you are simply listing them sequentially, trying to figure out whether x is even, THEN figure out whether x is odd. Unsure why it is not working. Can someone explain why or operators must be used as opposed to listing methods sequentially, when trying to search for multiple conditions?
Ruby has an implicit return where the last executed line in a method or a block will be the line that is returned. With this in mind
variable = a.find_all do |x|
x.even?
x.odd?
end
Will only regard the line x.odd? when it comes to keeping that. You could do it without an or operator like this
variable = a.find_all do |x|
if x.even?
true
else
x.odd?
end
end
For this if x.even? is true, then true will be returned as that is the last line of code run inside the block. If x.even? is false, then x.odd? will be returned as that is the last line of code run inside the block. If you are trying to check for multiple conditions using || is efficient but you can also do something like this.
Let's say I have the array a = ['dog', 2, 3.4, 'PIZZA', false, nil]. Let's say that I want all lowercase strings, all integers, and all nil values. I can do this
a.find_all do |i|
if i.is_a? String
i == i.downcase
elsif i.is_a? Numeric
i == i.to_i
else
i.nil?
end
end
This would return ['dog', 2, nil].
The find_all methods iterates over each element of the collection, using the return value of the block you pass to it to test whether the element matches. Then returns a new array with the matching elements.
If you use this code:
variable = x.find_all do |x|
x.even?
x.odd?
end
the return value of the block is x.odd?, as in ruby unless you use the return operator explicitly, the last expression of a block or method is returned.
If you want to group the elements of a collection by whether it is odd or even you should use some other approach. For example you could use group_by:
[1,2,3].group_by { |x| x.even? }
=> {false=>[1, 3], true=>[2]}
[1,2,3].group_by { |x| x.even? ? :even : :odd }
=> {:odd=>[1, 3], :even=>[2]}

iterate array combination method with .any method

Is there anyway to iterate through different combinations of arrays?
I'm writing a program that returns true if the largest number in an array can be the sum of any of the members of the array.
This is my code: (forgive me, i learned how to program 2 weeks ago for the first time)
def ArrayAdditionI(arr)
arr=arr.sort
largest=arr.pop
n=arr.length
for i in 1..n
if arr.combination(i).to_a.any? {|array| array.inject(:+)==largest}
return true
else
return false
end
end
end
i tested it for
a = [1,2,3,4]
and it returned false even though clearly, 3+1 = 4.
When I change the above code from arr.combination(i) to arr.combination(2) its returns true. So I'm guessing it has something to do with the combination method not being able to be looped. Any suggestions?
You have return false in the wrong place. As it is, false is returned is there is no combination of one element (i.e., one element other than the one you've removed after sorting) that sums (i.e., is equal to) largest. Rather you want to return false only if no combination of any size sums to largest. This is what you need:
def max_match?(arr)
arr=arr.sort
largest=arr.pop
n=arr.length
for i in 1..n
return true if arr.combination(i).any? {|array|
array.inject(:+)==largest}
end
false
end
arr = [1,4,7,3,5,2,13]
max_match?(arr) #=> true
arr = [1,3,4,7,59]
max_match?(arr) #=> false
A few notes:
lower case letters and optional underscores are used for names of methods. You can also put a question (?) or explanation (!) mark at the end. Here a question mark seems appropriate.
to_a is not needed. Enumerable methods (e.g., any?) can have Enumerators as receivers.
sorting is expensive and unnecessary. Instead, just get the max value and remove it from the array. (Aside: you didn't say what happens if the maximum value appears more than once. See the code below and the last sentence.)
you don't need n=arr.length. for i in 1..arr.length is enough, except...
for ... is rarely used. Rubyists tend to use each instead, or one of the many methods from the Enumerable (mix-in) module (all of which invoke each).
you don't need return false because Ruby returns the value of the last statement evaluated, which is false if the method does not return true earlier.
Here's a more Ruby-like way to do that:
def max_match?(arr)
mx = arr.max
whats_left = arr - [mx]
(1..whats_left.size).any? {|n| whats_left.combination(n).any? {|c|
c.reduce(:+) == mx }}
end
arr = [1,4,7,3,5,2,13]
max_match?(arr) #=> true
arr = [1,3,4,7,59]
max_match?(arr) #=> false
If you wish this to return true when arr contains more than one value equal to mx, insert the following after mx = arr.max:
return true if arr.count(mx) > 1

Cannot delete a certain array value introduced from console

I have this file.rb and when I run it from terminal, I want to delete a certain input value. However, the array remains the same. Any help, please?
def delete
print "Introduce the parameter for the delete action"
delete_value = gets.chomp
p #array.select { |e| e!= "#{delete_value}"}
##second_array = #array.reject! {|x| x == "#{delete_value}" }
#puts #second_array
end
You have an array of numbers:
#array = [-3,6,5,3,10,6,2,3,9,-3,-2,-5]
But your delete_value is a string:
delete_value = gets.chomp
a == b is false for every Fixnum a and String b (and similarly a != b is always true) so you'll need to convert b to a number with something like:
delete_value = gets.to_i
#array.reject! { |x| x == delete_value }
Ruby doesn't automatically convert between strings and numbers the way some languages will, you have to make the types match and perform the type conversions by hand.
This method return a new array with all matches. Your original array will indeed not change at all.
For further reference: http://ruby-doc.org/core-2.0.0/Enumerable.html#method-i-select

how do i print the element of an array without brackets or quotes?

This is driving me crazy. I'm basically trying to check if saved_category_parent matches parsed_category_parent
it says saved_category_parent belongs to class Array, while parsed_category_parent (scraped with nokogiri) says its a string.
So when I try to check the following it always returns false because its comparing first with ["first"]
I just need to remove the stupid brackets. i tried to_s and it actually makes it worse... it adds more parenthesis and more brackets.
if saved_category_parent == parsed_category_parent && saved_category == parsed_category
//code
end
heres my other code
categories = ["#first > sub-cat", "#second > sub-cat-2"]
# Parse through saved categories and break them up
categories.each do |category|
saved_category_parent = category.scan(/#([^ ]*)/)[0]
saved_category = category.scan(/.* > (.*)$/)[0]
#rss = Nokogiri::HTML(open(open(link.get_attribute('href'))))
#rss.css('.col').each do |forumblock|
parsed_category_parent = forumblock.css('h4 a').inner_text
forumblock.css('li a').each do |forumlink|
parsed_category = forumlink.content
# p saved_category_parent
# p parsed_category_parent
# p saved_category
# p parsed_category
p saved_category_parent
p saved_category
end
end
end
If your array only has one element you can do this:
# creating the values manually for the example
parsed_category_parent = "first"
saved_category_parent = ["first"]
# solution
parsed_category_parent = saved_category_parent[0]
You can try it in IRB to see that it works.
By using the [] operator you are accessing the first element of the array which is a string, thus comparing two strings together rather than comparing a string with an array containing a string.
You could also use other methods of accessing elements in an array like "first".
Use Array#first to get the first (or only) element of the array:
irb> ["first"].first
=> "first"

Resources