This method is supposed to take a string and detect if the brackets '(' '{' '[' in the string are closing properly with the corresponding (opposite) brackets.
First, is there a more elegant, compact way to write this bit without using all the "or"s (||):
split_array.each do |i|
if (i == "{" || i == "(" || i == "[")
left.push(i)
else (i == "}" || i == ")" || i == "]")
right.push(i)
end
end
My second question is, is this code terrible (see below)? It seems I should be able to write this in way fewer lines, but logically, I haven't come up with another solution (yet.)
The code works for most tests, but it returns false for this test (see all driver tests at bottom): p valid_string?("[ ( text ) {} ]") == true
Any critique would be greatly appreciated!
(also, if there is a better section to post this, please let me know)
Thanks!
def valid_string?(string)
opposites = { "[" => "]", "{" => "}", "(" => ")", "]" => "[", "}" => "{", ")" => "(" }
left = Array.new
right = Array.new
return_val = true
split_array = string.split(//)
split_array.delete_if { |e| e.match(/\s/) }
split_array.each do |i|
if (i == "{" || i == "(" || i == "[")
left.push(i)
else (i == "}" || i == ")" || i == "]")
right.push(i)
end
end
# p left
# p right
left.each_index do |i|
if left[i] != opposites[right[i]]
return_val = false
end
end
return_val
end
p valid_string?("[ ] } ]") == false
p valid_string?("[ ]") == true
p valid_string?("[ ") == false
p valid_string?("[ ( text ) {} ]") == true
p valid_string?("[ ( text { ) } ]") == false
p valid_string?("[ (] {}") == false
p valid_string?("[ ( ) ") == false
-------Updated: After trying some different approaches, my refactor is this:-----------
def valid_string?(str)
mirrored = { "[" => "]", "{" => "}", "(" => ")" }
open_brackets = Array.new
split_str_array = str.split("")
split_str_array.each do |bracket|
if bracket.match(/[\[|\{|\(]/) then open_brackets.push(bracket)
elsif bracket.match(/[\]|\}|\)]/)
return false if mirrored[open_brackets.pop] != bracket
end
end
open_brackets.empty?
end
My approach is as below :
def valid_string?(string)
open_paren = ['[','{','(']
close_paren = [']','}',')']
open_close_hash = {"]"=>"[", "}"=>"{", ")"=>"("}
stack = []
regex = Regexp.union(close_paren+open_paren)
string.scan(regex).each do |char|
if open_paren.include? char
stack.push(char)
elsif close_paren.include? char
pop_val = stack.pop
return false if pop_val != open_close_hash[char]
end
end
open_paren.none? { |paren| stack.include? paren }
end
valid_string?("[ ] } ]") # => false
valid_string?("[ ]") # => true
valid_string?("[ ") # => false
valid_string?("[ (] {}") # => false
valid_string?("[ ( ) ") # => false
valid_string?("[ ( text { ) } ]") # => false
valid_string?("[ ( text ) {} ]") # => true
Algorithm :
Declare a character stack S.
Now traverse the expression string exp.
If the current character is a starting bracket (‘(‘ or ‘{‘ or ‘[') then push it to stack.
If the current character is a closing bracket (')' or '}' or ']') then pop from stack and if the popped character is the matching starting bracket then fine else parenthesis are not balanced.
After complete traversal, if there is some starting bracket left in
stack then “not balanced”
The shortest regex solution is probably:
def valid_string? orig
str = orig.dup
re = /\([^\[\](){}]*\)|\[[^\[\](){}]*\]|\{[^\[\](){}]*\}/
str[re] = '' while str[re]
!str[/[\[\](){}]/]
end
How about:
class Brackets
def self.paired?(s)
stack = []
brackets = { '{' => '}', '[' => ']', '(' => ')' }
s.each_char do |char|
if brackets.key?(char)
stack.push(char)
elsif brackets.values.include?(char)
return false if brackets.key(char) != stack.pop
end
end
stack.empty?
end
end
Brackets.paired?("[ ] } ]") # => false
Brackets.paired?("[ ]") # => true
Brackets.paired?("[ ") # => false
Brackets.paired?("[ (] {}") # => false
Brackets.paired?("[ ( ) ") # => false
Brackets.paired?("[ ( text { ) } ]") # => false
Brackets.paired?("[ ( text ) {} ]") # => true
You can try this approach:
def balanced_brackets?(string)
# your code here
stack = []
opening_bracket = ['{','[', '(']
closing_bracket = ['}', ']', ')']
string.chars.each do |char|
if opening_bracket.include?(char)
stack << char
elsif closing_bracket.include?(char)
value = stack.pop
return false if opening_bracket.index(value) != closing_bracket.index(char)
end
end
stack.empty?
end
if you want to understand pseudo code try this link from coursera (starts at 0:56).
Another way:
s = str.gsub(/[^\{\}\[\]\(\)]/, '')
while s.gsub!(/\{\}|\[\]|\(\)/, ''); end
s.empty?
Ex 1
str = "(a ()bb [cc{cb (vv) x} c ]ss) "
s = str.gsub(/[^\{\}\[\]\(\)]/, '') #=> "(()[{()}])"
while s.gsub!(/\{\}|\[\]|\(\)/, '') do; end
s => "([{}])" => "([])" => "()" => "" gsub!() => nil
s.empty? #=> true
Ex 2
str = "(a ()bb [cc{cb (vv) x] c }ss) "
s = str.gsub(/[^\{\}\[\]\(\)]/, '') #=> "(()[{()]})"
while s.gsub!(/\{\}|\[\]|\(\)/, '') do; end
s => "([{]})" gsub!() => nil
s.empty? #=> false
This should provide the same functionality
def valid_string?(string)
#assume validity
#valid = true
#empty array will be populated inside the loop
#open_characters = []
#set up a hash to translate the open character to a closing character
translate_open_closed = {"{" => "}","["=>"]","("=>")"}
#create an array from the string loop through each item
string.split('').each do |e|
#adding it to the open_characters array if it is an opening character
#open_characters << e if e=~ /[\[\{\(]/
#if it is a closing character then translate the last open_character to
#a closing character and compare them to make sure characters are closed in order
#the result of this comparison is applied to the valid variable
#valid &= e == translate_open_closed[#open_characters.pop] if e=~ /[\]\}\)]/
end
#return validity and make sure all open characters have been matched
#valid &= #open_characters.empty?
end
You could also do this with inject but it would be a bit less transparent.
I was given this as part of a simulated interview coding challenge. In my case, there was also a parens map passed in { "(" => ")", "[" => "]" }, meaning types of parentheses could vary.
def balanced_parens(string, parens_map)
# where we throw opening parens
opening_parens = []
i = 0
while i < string.length
# if current index is opening paren add to array
if parens_map.keys.include? string[i]
opening_parens << string[i]
# if current index is closing paren, remove last item from opening_array
elsif parens_map.values.include? string[i]
popped_paren = opening_parens.pop
# checking that closing parens at current index is a match for last open parens in opening_array
return false if string[i] != parens_map[popped_paren]
end
i += 1
end
# if opening_parens array is empty, all parens have been matched (&& value = true)
opening_parens.empty?
end
def valid_string?(exp)
return false if exp.size % 2 != 0
curly = "{}"
square = "[]"
parenthesis = "()"
emptystr = ""
loop do
old_exp = exp
exp = exp.sub(curly, emptystr)
break if exp == emptystr
exp = exp.sub(square, emptystr)
break if exp == emptystr
exp = exp.sub(parenthesis, emptystr)
break if exp == emptystr || exp == old_exp
end
exp == emptystr
end
Related
Write a method that returns the no of various lowercase, uppercase, digits and special characters used in the string. Make use of Ranges.
Input = "heLLo Every1"
I am making using of ranges and case method in solution provided.
Solution:
class String
def character_count
uppercase_count = 0
lowercase_count = 0
digit_count = 0
uppercase_range = Range.new('A', 'Z')
lowercase_range = Range.new('a', 'z')
digit_range = Range.new('0', '9')
special_character_count = 0
each_char do |item|
case item
when uppercase_range
uppercase_count += 1
when lowercase_range
lowercase_count += 1
when digit_range
digit_count += 1
else
special_character_count += 1
end
end
[lowercase_count, uppercase_count, digit_count, special_character_count]
end
end
if ARGV.empty?
puts 'Please provide an input'
else
string = ARGV[0]
count_array = string.character_count
puts "Lowercase characters = #{count_array[0]}"
puts "Uppercase characters = #{count_array[1]}"
puts "Numeric characters = #{count_array[2]}"
puts "Special characters = #{count_array[3]}"
end
Code is working.
Yes
class String
def character_count
counters = Hash.new(0)
each_char do |item|
case item
when 'A'..'Z'
counters[:uppercase] += 1
when 'a'..'z'
counters[:lowercase] += 1
when '0'..'9'
counters[:digit] += 1
else
counters[:special] += 1
end
end
counters.values_at(:uppercase, :lowercase, :digit, :special)
end
end
if ARGV.empty?
puts 'Please provide an input'
else
string = ARGV[0]
uppercase, lowercase, digit, special = string.character_count
puts "Lowercase characters = #{lowercase}"
puts "Uppercase characters = #{uppercase}"
puts "Numeric characters = #{digit}"
puts "Special characters = #{special}"
end
You can instead use regex in better way as following,
type = { special: /[^0-9A-Za-z]/, numeric: /[0-9]/, uppercase: /[A-Z]/, lowercase: /[a-z]/ }
'Hello World'.scan(type[:special]).count
# => 1
'Hello World'.scan(type[:numeric]).count
# => 0
'Hello World'.scan(type[:uppercase]).count
# => 2
'Hello World'.scan(type[:lowercase]).count
# => 8
Other option.
First, map your ranges into an Hash:
mapping = { upper: ('A'..'Z'), lower: ('a'..'z'), digits: ('0'..'9'), specials: nil }
Then initialize the recipient Hash to default 0:
res = Hash.new(0)
Finally, map the chars of the input:
input = "heLLo Every1"
input.chars.each { |e| res[(mapping.find { |k, v| v.to_a.include? e } || [:specials]).first ] += 1 }
res
#=> {:upper=>3, :lower=>7, :digits=>1, :specials=>1}
str = "Agent 007 was on the trail of a member of SPECTRE"
str.each_char.with_object(Hash.new(0)) do |c,h|
h[ case c
when /\d/ then :digit
when /\p{Lu}/ then :uppercase
when /\p{Ll}/ then :downcase
else :special
end
] += 1
end
end
#=> {:uppercase=>8, :downcase=>28, :special=>10, :digit=>3}
The Following program is intended to iterate over the holiday_hash, capitalise all keys and values and puts them out:
def all_supplies_in_holidays(holiday_hash)
holiday_hash.each do |key, value|
key_string = key.to_s
key_string.capitalize!
puts "#{key_string}:"
value.each do |key2, value2|
if key2 == :new_year || :fourth_of_july || :memorial_day
key_to_string = key2.to_s
key_string1 = key_to_string.split
final_array = []
key_string1.each do |splitted_string|
final_array = splitted_string.capitalize!
end
final_string = final_array.join(" ")
print "#{final_string1}:"
else
key_string1 = key2.to_s
print "#{key_string1}"
end
value2.each do |array_value|
new_array_capitalized = []
new_array_capitalized << array_value.capitalize!
new_array.join(" ")
end
end
end
end
The expected output format is:
Winter:
Christmas: Lights, Wreath
New Years: Party Hats
Summer:
Fourth of July: Fireworks, BBQ
Fall:
Thanksgiving: Turkey
Spring:
Memorial Day: BBQ
The holiday_hash is as follows:
{
:winter => {
:christmas => ["Lights", "Wreath"],
:new_years => ["Party Hats"]
},
:summer => {
:fourth_of_july => ["Fireworks", "BBQ"]
},
:fall => {
:thanksgiving => ["Turkey"]
},
:spring => {
:memorial_day => ["BBQ"]
}
}
The problem is:
The if block executes even if the conditions fails to evaluate to true.
Suggestions needed:
How can I simplify the process of capitalising symbols who have two words in them like :new_york to be capitalised to New York? (As the #capitalised method will return New york)
The if block executes even if the conditions fails to evaluate to true
Let's see:
key2 = :new_year
key2 == :new_year || :fourth_of_july || :memorial_day
#=> true
and now a key that is supposed to return false:
key2 = :thanksgiving
key2 == :new_year || :fourth_of_july || :memorial_day
#=> :fourth_of_july
That's not your expected result, but your assumption isn't correct either: the if block is executed simply because the condition is always truthy.
Why? Because it's equivalent to:
false || :fourth_of_july || :memorial_day
#=> :fourth_of_july
You want:
key2 == :new_year || key2 == :fourth_of_july || key2 == :memorial_day
#=> false
Or a little shorter:
[:new_year, :fourth_of_july, :memorial_day].include? key2
#=> false
How can I simplify the process of capitalising symbols who have two words in them [...]
I'd split them by underscore, capitalize each word and join the result:
:new_year
.to_s #=> "new_year"
.split('_') #=> ["new", "year"]
.map(&:capitalize) #=> ["New", "Year"]
.join(' ') #=> "New Year"
I've separated the method calls to show the intermediate results. You can write the above in one line:
:new_year.to_s.split('_').map(&:capitalize).join(' ')
#=> "New Year"
As part of learning Ruby am trying to implement a basic interpreter which reads input and do basic arithmetic calculations. So far basic arithmetic operations are working but having problem in operator precedence. Which is not handled yet. This is the code. Am at a beginner level. Any mistakes in this code are due to my lack of knowledge. How this code can be modified to handle operator precedence.
Sample output
2+2+2 = 6 #correct
10+10/2 = 10 # incorrect as in irb answer must be 15
Github Repo of this interpreter
=begin
Basic calculator Interpreter
can add, substract, multiply , divide with any number of operands at a time
Drawback : Lacks operator precedence
=end
class Interpreter
attr_accessor :input
def initialize
#input = gets.chomp
end
def intepret
first_operand = []
f = []
operator = '+'
array = Array.new
lc = 0
#input.split.join.split("").each_with_index.map do |i, index|
if i.is_number?
first_operand.push(i)
if index == #input.length-1
array.push(first_operand.join("").to_i)
end
elsif i.is_plus?
f = first_operand
first_operand = nil
first_operand = []
array.push(f.join("").to_i)
array.push("+")
elsif i.is_minus?
f = first_operand
first_operand = nil
first_operand = []
operator = '-'
array.push(f.join("").to_i)
array.push("-")
elsif i.is_multi?
f = first_operand
first_operand = nil
first_operand = []
operator = '*'
array.push(f.join("").to_i)
array.push("*")
elsif i.is_divide?
f = first_operand
first_operand = nil
first_operand = []
operator = '/'
array.push(f.join("").to_i)
array.push("/")
else
puts "Illegal input exiting.."
exit
end
lc = lc+1
end
#apply the appropriate operation on the inputs based on the operand
#puts "=======TOKENS======"
#puts array.inspect
result = 0
array.each_with_index.map do |x, key|
result = x if key == 0
if x == '+'
if key == 0
result = add(result, array[key+1])
else
result = add(result, array [key+1])
end
elsif x == '-'
if key == 0
result = minus(result, array[key+1])
else
result = minus(result, array [key+1])
end
elsif x == '*'
if key == 0
result = multi(result, array[key+1])
else
result = multi(result, array [key+1])
end
elsif x == '/'
begin
if key == 0
result = divide(result, array[key+1])
else
result = divide(result, array [key+1])
end
rescue
puts "Zero Divsion error"
exit
end
end
end
puts "Result is: "+result.to_s
end
def print_token(type, value)
puts type + ' '+ value
end
def add(f,s)
return f.to_i + s.to_i
end
def minus(f,s)
return f.to_i - s.to_i
end
def multi(f,s)
return f.to_i * s.to_i
end
def divide(f,s)
return f.to_i / s.to_i
end
end
# Override the string class, to directly use methods like obj.is_number? rather than is_number?(obj)
class String
def is_number?
true if Float(self) rescue false
end
def is_plus?
true if self == '+' rescue false
end
def is_minus?
true if self == '-' rescue false
end
def is_multi?
true if self == '*' rescue false
end
def is_divide?
true if self == '/' rescue false
end
end
#continue accepting inputs until exit CTRL + D
while true
print 'pck>:'
i_obj = Interpreter.new
i_obj.intepret
end
First, process the input using the Shunting-yard algorithm. This should give a list of tokens in Reverse Polish notation (RPN). Then you can evaluate the RPN expression.
I need help on Writing a method that takes a string in and returns true if the letter "z" appears within three letters after an "a". You may assume that the string contains only lowercase letters. here's what I have:
def nearby_az(string)
string.downcase!
i = 0
while i < string.length
if (string[i] == "a" && string[i] == "z")
true
else
false
end
end
end
puts('nearby_az("baz") == true: ' + (nearby_az('baz') == true).to_s)
puts('nearby_az("abz") == true: ' + (nearby_az('abz') == true).to_s)
puts('nearby_az("abcz") == true: ' + (nearby_az('abcz') == true).to_s)
puts('nearby_az("a") == false: ' + (nearby_az('a') == false).to_s)
puts('nearby_az("z") == false: ' + (nearby_az('z') == false).to_s)
puts('nearby_az("za") == false: ' + (nearby_az('za') == false).to_s)
A regular expression would be the best for this. Try
def nearby_az(string)
(string =~ /a.{0,2}z/) != nil
end
EDIT:
as per the "if statement required requirement" :)
def nearby_az(string)
if (string =~ /a.{0,2}z/) != nil
return true
end
return false
end
The way this code works is it searches the input string for an "a". After that, the period indicates that you can have any character. After that you have {0,2} which is a modifier of the period indicating you can have 0 to 2 of any character. After this you must have a "z", and this fulfills your must have a z within 3 characters of an "a".
I've saved this regex to regex101 here so you can try various inputs as well as change the regular expression around to understand it better.
To fix you code you need to:
increment i at the end of the loop.
search the z letter within the 3 next letters
return true when condition is met
return false when getting out of the loop
Here is what it should look like:
def nearby_az(string)
string.downcase!
i = 0
while i < string.length do
return true if string[i] == "a" && string[i+1,3].include?(?z)
i+=1
end
return false
end
Write a method 'valid_string?' that accepts a string. It returns true if the brackets, parentheses, and curly braces close correctly. It returns false otherwise.
valid_string?("[ ]") # returns true
valid_string?("[ ") # returns false
valid_string?("[ ( text ) {} ]") # returns true
valid_string?("[ ( text { ) } ]") # returns false
My code: Is returning false for everything. Even tried using explicit booleans for individual cases {} || () ||, etc. Did not work. Either returns true or false for everything. Is it my driver code?
def valid_string?(str)
if str == ("\[\s+]")
true
else
false
end
end
UPDATED SOLUTION:------------------------------------------------
Yes! #match definitely worked out better! Although my last line of test code is evaluating to true. When it should be false. . .
def valid_string?(str)
if str.match "(\\[.+\\])" || "|(\\(\\))" || "|({})"
return true
else
return false
end
end
puts valid_string?("[ ]") # returns true
puts valid_string?("[ ") # returns false
puts valid_string?("[ ( text ) {} ]") # returns true
puts valid_string?("[ ( text { ) } ]") # returns false
I think it might be complicated to use regex to solve this problem. Here is a potential solution: You may use a stack to record the left symbol like {, [, ( in the traverse. Each time you met the right symbol, just check whether the symbol on the stack top matches this right symbol. Simply return false if not match.
Below is my code:
def valid_string?(str)
stack = []
symbols = { '{' => '}', '[' => ']', '(' => ')' }
str.each_char do |c|
stack << c if symbols.key?(c)
return false if symbols.key(c) && symbols.key(c) != stack.pop
end
stack.empty?
end
puts valid_string?('[ ]') # returns true
puts valid_string?('[ ') # returns false
puts valid_string?('[ ( text ) {} ]') # returns true
puts valid_string?('[ ( text { ) } ]') # returns false
Just because it was fun, I went ahead and solved this The Ruby Way :)
class Brackets
class Bracket
def initialize(open, close)
#open = open
#close = close
#match_count = 0
end
attr_reader :match_count, :open, :close
def check(c)
#match_count += 1 if c == #open
#match_count -= 1 if c == #close
end
end
def initialize
#brackets = []
#stack = []
#valid = true
end
def add(open, close)
#brackets << Bracket.new(open,close)
end
def check(c)
#brackets.each do |b|
b.check(c)
#stack.push(c) if c == b.open
#valid = false if c == b.close and #stack.pop != b.open
end
end
def valid?
total = 0
#brackets.each { |b| total += b.match_count }
total == 0 && #valid == true
end
end
def valid_string?(str)
brackets = Brackets.new
brackets.add('[', ']')
brackets.add('{', '}')
brackets.add('(', ')')
str.each_char { |c| brackets.check(c) }
brackets.valid?
end
# Our tests
puts valid_string?("[ ]") ? 'true' : 'false' # returns true
puts valid_string?("[ ") ? 'true' : 'false' # returns false
puts valid_string?("[ ( text ) {} ]") ? 'true' : 'false' # returns true
puts valid_string?("[ ( text { ) } ]") ? 'true' : 'false' # returns false
puts valid_string?("[ ( text { } ) ]") ? 'true' : 'false' # returns true
Here's a way that doesn't use regex:
def valid_string?(str)
strim = str.gsub(/[^\[\]\(\)\{\}]/,'')
return true if strim.empty?
return false if strim.size.odd?
loop do
s = strim.gsub('()','').gsub('[]','').gsub('{}','')
return true if s.empty?
return false if s == strim
strim = s
end
end
p valid_string?("[ ]") # => true
p valid_string?("[ ") # => false
p valid_string?("[ ( text ) {} ]") # => true
p valid_string?("[ ( text { ) } ]") # => false
p valid_string?("[ ( text { more text { (more text) }} )]") # => true
First remove all characters other than those in "()[]{}".
If the remaining string is empty, return true
If the remaining string contains an odd number of characters, return false.
Continue removing adjacent pairs '()', '[]' and '[]' until either the string is empty, in which case return true, or no more adjacent pairs can be removed and the string is non-empty, in which case return false.
How about a simple counting routine?
def valid_string?(str)
match_count = 0
str.each_char do |c|
match_count += 1 if [ '[', '{', '(' ].include?(c)
match_count -= 1 if [ ']', '}', ')' ].include?(c)
end
return match_count == 0
end
I found recursion to work really well in this situation. Hope this helps!
def valid_string?(string)
bracket_string = string.gsub(/[^\[\]\(\)\{\}]/,'').gsub('()','').gsub('[]','').gsub('{}','')
return true if bracket_string.empty?
return false if bracket_string.length.odd?
return false if bracket_string.include?(string)
valid_string?(bracket_string)
end