I have a method that I want to use to replace characters in a string:
def complexity_level_two
replacements = {
'i' => 'eye', 'e' => 'eei',
'a' => 'aya', 'o' => 'oha'}
word = "Cocoa!55"
word_arr = word.split('')
results = []
word_arr.each { |char|
if replacements[char] != nil
results.push(char.to_s.gsub!(replacements[char]))
else
results.push(char)
end
}
end
My desired output for the string should be: Cohacohaa!55
However when I run this method it will not replace the characters and only outputs the string:
C
o
c
o
a
!
5
5
What am I doing wrong to where this method will not replace the correct characters inside of the string to match that in the hash and how can I fix this to get the desired output?
replacements = {
'i' => 'eye', 'e' => 'eei',
'a' => 'aya', 'o' => 'oha'}
word = "Cocoa!55"
word.gsub(Regexp.union(replacements.keys), replacements)
#⇒ "Cohacohaaya!55"
Regexp::union, String#gsub with hash.
replacements = { 'i' => 'eye', 'e' => 'eei', 'a' => 'aya', 'o' => 'oha' }.
tap { |h| h.default_proc = ->(h,k) { k } }
"Cocoa!55".gsub(/./, replacements)
#=> "Cohacohaaya!55"
See Hash#default_proc= and Object#tap.
gsub examines each character of the string. If replacements has that character as a key, the character is replaced with the value of that key in replacements; else (because of the default proc), the character is replaced with itself (that is, left unchanged).
Another way would be to use Hash#fetch:
replacements = { 'i' => 'eye', 'e' => 'eei', 'a' => 'aya', 'o' => 'oha' }
"Cocoa!55".gsub(/./) { |s| replacements.fetch(s) { |c| c } }
#=> "Cohacohaaya!55"
which, for Ruby v2.2+ (when Object#itself made its debut), can be written
"Cocoa!55".gsub(/./) { |s| replacements.fetch(s, &:itself) }
you can try to do this:
my_subs = { 'i' => 'eye', 'e' => 'eei','a' => 'aya', 'o' => 'oha' }
my_word = "Cocoa!55"
my_word.split('').map{|i| my_subs[i] || i}.join
=> "Cohacohaaya!55"
Constructing a method
Define your method with word and subs parameters:
def char_replacer word, subs
word.chars.map { |c| subs.key?(c) ? subs[c] : c }.join
end
Here we've used the ternary operator which is essentially an if-else expression in a more compact form. Key methods to note are String#chars, Array#map, Hash#key?, see ruby-docs for more info on these. Now with this all set up, you can call your method passing a word string and the subs hash of your choosing.
Example 1
my_subs = { 'i' => 'eye', 'e' => 'eei','a' => 'aya', 'o' => 'oha' }
my_word = "Cocoa!55"
char_replacer my_word, my_subs #=> "Cohacohaaya!55"
Example 2
my_subs = { 'a' => 'p', 'e' => 'c' }
my_word = "Cocoa!55"
char_replacer my_word, my_subs #=> "Cocop!55"
Related
In ruby, I want to substitute some letters in a string, is there a better way of doing this?
string = "my random string"
string.gsub(/a/, "#").gsub(/i/, "1").gsub(/o/, "0")`
And if I want to substitute both "a" and "A" with a "#", I know I can do .gsub(/a/i, "#"), but what if I want to substitute every "a" with an "e" and every "A" with an "E"? Is there a way of abstracting it instead of specifying both like .gsub(/a/, "e").gsub(/A/, "E")?
You can use a Hash. eg:
h = {'a' => '#', 'b' => 'B', 'A' => 'E'}
"aAbBcC".gsub(/[abA]/, h)
# => "#EBBcC"
Not really an answer to your question, but more an other way to proceed: use the translation:
'aaAA'.tr('aA', 'eE')
# => 'eeEE'
For the same transformation, you can also use the ascii table:
'aaAA'.gsub(/a/i) {|c| (c.ord + 4).chr}
# => 'eeEE'
other example (the last character is used by default):
'aAaabbXXX'.tr('baA', 'B#')
# => '####BBXXX'
Here are two variants of #Santosh's answer:
str ="aAbBcC"
h = {'a' => '#', 'b' => 'B', 'A' => 'E'}
#1
str.gsub(/[#{h.keys.join}]/, h) #=> "#EBBcC"
#2
h.default_proc = ->(_,k) { k }
str.gsub(/./, h) #=> "#EBBcC"
These offer better maintainability should h could change in future
You can also pass gsub a block
"my random string".gsub(/[aoi]/) do |match|
case match; when "a"; "#"; when "o"; "0"; when "i"; "I" end
end
# => "my r#nd0m strIng"
The use of a hash is of course much more elegant in this case, but if you have complex rules of substitution it can come in handy to dedicate a class to it.
"my random string".gsub(/[aoi]/) {|match| Substitute.new(match).result}
# => "my raws0m strAINng"
I have string like this
hi, i am not coming today!
and i have an array of characters like this:
['a','e','i','o','u']
now i want to find the first occurrence of any word from array in string.
If it was only word i'd have been able to do it like this:
'string'.index 'c'
s = 'hi, i am not coming today!'
['a','e','i','o','u'].map { |c| [c, s.index(c)] }.to_h
#⇒ {
# "a" => 6,
# "e" => nil,
# "i" => 1,
# "o" => 10,
# "u" => nil
# }
To find the first occurence of any character from an array:
['a','e','i','o','u'].map { |c| s.index(c) }.compact.min
#⇒ 1
UPD Something different:
idx = str.split('').each_with_index do |c, i|
break i if ['a','e','i','o','u'].include? c
end
idx.is_a?(Numeric) ? idx : nil
str =~ /#{['a','e','i','o','u'].join('|')}/
str.index Regexp.union(['a','e','i','o','u']) # credits #steenslag
I have this hash:
HASH = {
'x' => { :amount => 0 },
'c' => { :amount => 5 },
'q' => { :amount => 10 },
'y' => { :amount => 20 },
'n' => { :amount => 50 }
}
How can I get the key with the next highest amount from the hash?
For example, if I supply x, it should return c. If there is no higher amount, then the key with the lowest amount should be returned. That means when I supply n, then x would be returned.
Can anybody help?
I'd use something like this:
def next_higher(key)
amount = HASH[key][:amount]
sorted = HASH.sort_by { |_, v| v[:amount] }
sorted.find(sorted.method(:first)) { |_, v| v[:amount] > amount }.first
end
next_higher "x" #=> "c"
next_higher "n" #=> "x"
I'd do something like this:
def find_next_by_amount(hash, key)
sorted = hash.sort_by { |_, v| v[:amount] }
index_of_next = sorted.index { |k, _| k == key }.next
sorted.fetch(index_of_next, sorted.first).first
end
find_next_by_amount(HASH, 'x')
# => "c"
find_next_by_amount(HASH, 'n')
# => "x"
Something like that:
def next(key)
amount = HASH[key][:amount]
kv_pairs = HASH.select{ |k, v| v[:amount] > amount }
result = kv_pairs.empty? ? HASH.first.first : kv_pairs.min_by{ |k, v| v}.first
end
I'm curious, why would you want something like that? Maybe there is better solution to underlying task.
EDIT: Realized that hash isn't necessary sorted by amount, adapted code for unsorted hashes.
One way:
A = HASH.sort_by { |_,h| h[:amount] }.map(&:first)
#=> ['x', 'c', 'q', 'y', 'n']
(If HASH's keys are already in the correct order, this is is just A = HASH.keys.)
def next_one(x)
A[(A.index(x)+1)%A.size]
end
next_one 'x' #=> 'c'
next_one 'q' #=> 'y'
next_one 'n' #=> 'x'
Alternatively, you could create a hash instead of a method:
e = A.cycle
#=> #<Enumerator: ["x", "c", "q", "y", "n"]:cycle>
g = A.size.times.with_object({}) { |_,g| g.update(e.next=>e.peek) }
#=> {"x"=>"c", "c"=>"q", "q"=>"y", "y"=>"n", "n"=>"x"}
Trying to refactor this into one line to get all vowels in a string to be capitalized. I tried using a hash, but that failed. Still too new at Ruby to know of any alternatives, despite my best efforts to look it up. something like.... str.gsub!(/aeiou/
def LetterChanges(str)
str.gsub!(/a/, "A") if str.include? "a"
str.gsub!(/e/, "E") if str.include? "e"
str.gsub!(/i/, "I") if str.include? "i"
str.gsub!(/o/, "O") if str.include? "o"
str.gsub!(/u/, "U") if str.include? "u"
puts str
end
The best way is
str.tr('aeiou', 'AEIOU')
String#tr
Returns a copy of str with the characters in from_str replaced by the corresponding characters in to_str. If to_str is shorter than from_str, it is padded with its last character in order to maintain the correspondence.
You can use gsub's second parameter, which is a replacement hash:
str.gsub!(/[aeiou]/, 'a' => 'A', 'e' => 'E', 'i' => 'I', 'o' => 'O', 'u' => 'U')
or, alternatively, pass a block:
str.gsub!(/[aeiou]/, &:upcase)
Both will return:
'this is a test'.gsub!(/[aeiou]/, 'a' => 'A', 'e' => 'E', 'i' => 'I', 'o' => 'O', 'u' => 'U')
# => "thIs Is A tEst"
'this is a test'.gsub!(/[aeiou]/, &:upcase)
# => "thIs Is A tEst"
I have a hash that has a keys => meaning relation. Various elements of this hash are:
"fish" => "aquatic animal"
"fiend" => "bad person"
"great" => "remarkable"
I need to create a function find such that when I use this function find("fi"), it should give back both "fish" and "fiend" along with the definitions. So the output should be:
"fish" => "aquatic animal"
"fiend" => "bad person"
I am new to regular expressions and to Ruby.
hash.select{ |k,v| k.start_with? pattern }
You can do it as a single expression:
hash.select { |key, value| key.start_with? prefix }
Or if you're using Ruby 1.8:
hash.reject { |key, value| not key.start_with? prefix }
Examples:
{'foo' => 1, 'bar' => 2, 'baz' => 3}.select { |key, value| key.start_with? 'f' } # {'foo' => 1}
{'foo' => 1, 'bar' => 2, 'baz' => 3}.select { |key, value| key.start_with? 'b' } # {'bar' => 2, 'baz' => 3}
select would keep only pairs that don't match the condition in the block. str.start_with? prefix returns true if str starts with prefix (kind of obvious).
There is a slight awkwardness in the 1.8 code - I'm doing reject, instead of select and I need to negate the result from #start_with?. The reason is that in Ruby 1.8 Hash#reject returns a Hash, while Hash#select returns an array of pairs.