I'm trying to create a method that reorders all the vowels in a string as efficiently as possible. For example:
"you are incredible." returns "yae ere incridoblu."
This is what I've come up with:
def vowel_orderer(string)
vowels = ["a","e","i","o","u"]
ordered_vowels = string.scan(/[aeiou]/).sort
ordered_string = []
i = 0
j = 0
while i < string.length
if vowels.include?(string[i])
ordered_string << ordered_vowels[j]
j += 1
else
ordered_string << string[i] unless vowels.include?(string[i])
end
i += 1
end
puts ordered_string.join
end
I feel like there should be a shorter way to accomplish this, using something like gsub?
string = "you are incredible."
ordered_vowels = string.scan(/[aeiou]/).sort
string.gsub(/[aeiou]/){ordered_vowels.shift} # => "yae ere incridoblu."
def vowel_orderer_gsub(string)
ordered_vowels = string.scan(/[aeiou]/).sort { |x,y| y <=> x }
puts string.gsub(/[aeiou]/) { |match| ordered_vowels.pop }
end
1.9.3p448 :128 > vowel_orderer( "you are incredible." )
# yae ere incridoblu.
# => nil
1.9.3p448 :129 > vowel_orderer_gsub( "you are incredible." )
# yae ere incridoblu.
Related
# Character Counter
class String
def count_lcases
count(('a'..'z').to_a.join(''))
end
def count_upcases
count(('A'..'Z').to_a.join(''))
end
def count_num
count((0..9).to_a.join(''))
end
def count_spl_chars
length - count_lcases - count_upcases - count_num
end
end
input = ARGV[0]
if ARGV.empty?
puts 'Please provide an input'
exit
end
puts 'Lowercase characters = %d' % [input.count_lcases]
puts 'Uppercase characters = %d' % [input.count_upcases]
puts 'Numeric characters = %d' % [input.count_num]
puts 'Special characters = %d' % [input.count_spl_chars]
I used ranges to count characters but count function is called 3 times.
I can always use loops and count it one by one.I was wondering is there any way to optimize this?...
If you are using Ruby 2.7 you could use tally; the string's chars are just iterated one time.
def classify_char(c)
case c
when /[a-z]/ then :lcase
when /[A-Z]/ then :ucase
when /\d/ then :digit
else :other
end
end
p "asg3456 ERTYaeth".chars.map{|c| classify_char(c) }.tally
# => {:lcase=>7, :digit=>4, :other=>2, :ucase=>4}
If Ruby 2.3...2.7, this will work:
CHAR_CLASSES = {
lcase: ?a..?z,
ucase: ?A..?Z,
digit: ?0..?9,
}
p "asg3456 ERTYaeth".each_char.with_object(Hash.new(0)) { |c, o|
o[CHAR_CLASSES.find { |label, group| group === c }&.first || :other] += 1
}
For < 2.3,
p "asg3456 ERTYaeth".each_char.with_object(Hash.new(0)) { |c, o|
p = CHAR_CLASSES.find { |label, group| group === c }
o[p ? p.first : :other] += 1
}
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}
Here is my code in ruby for a word compression.
For any given word (e.g. abbbcca) the compressed word/output should be in the format as "letter+repetition" (for above example, output: a1b3c2a1).
Here I'm so close to the completion but my result isn't in the expected format. It's counting the whole letters in string.chars.each thus resulting output as a2b3c2a2.
Any help?
def string_compressor(string)
new_string = []
puts string.squeeze
string.squeeze.chars.each { |s|
count = 0
string.chars.each { |w|
if [s] == [w]
count += 1
end
}
new_string << "#{s}#{count}"
puts "#{new_string}"
}
if new_string.length > string.length
return string
elsif new_string.length < string.length
return new_string
else "Equal"
end
end
string_compressor("abbbcca")
'abbbcca'.chars.chunk{|c| c}.map{|c, a| [c, a.size]}.flatten.join
Adapted from a similar question.
Similar:
'abbbcca'.chars.chunk{|c| c}.map{|c, a| "#{c}#{a.size}"}.join
See chunk documentation
You can use a regular expression for that.
'abbbcca'.gsub(/(.)\1*/) { |m| "%s%d" % [m[0], m.size] }
#=> "a1b3c2a1"
The regular expression reads, "match any character, capturing it in group 1. Then match the contents of capture group 1 zero or more times".
As you said, your code counts every letter in the string, not just the one grouped next to one another.
Here's a modified version :
def display_count(count)
if count == 1
""
else
count.to_s
end
end
def string_compressor(string)
new_string = ''
last_char = nil
count = 0
string.chars.each do |char|
if char == last_char
count += 1
else
new_string << "#{last_char}#{display_count(count)}" if last_char
last_char = char
count = 1
end
end
new_string << "#{last_char}#{display_count(count)}" if last_char
new_string
end
p string_compressor('abbbcca') #=> "ab3c2a"
p string_compressor('aaaabbb') #=> "a4b3"
p string_compressor('aabb') #=> "a2b2"
p string_compressor('abc') #=> "abc"
Note that with display_count removing 1s from the string, new_string can never be longer than string. It also probably isn't a good idea to return Equal as a supposedly compressed string.
To decompress the string :
def string_decompressor(string)
string.gsub(/([a-z])(\d+)/i){$1*$2.to_i}
end
p string_decompressor("a5b11") #=> "aaaaabbbbbbbbbbb"
p string_decompressor("ab3c2a") #=> "abbbcca"
How would I do this in Ruby?
p "abc".all_possible_permutations
Would return:
[
"abc",
"acb",
"bca",
"bac",
"cba",
"cab",
]
Edit
Thanks to Jakub Hampl:
class String
def all_possible_permutations
self.chars.to_a.permutation.map(&:join)
end
end
%w[a b c].permutation.map &:join
If someone doesnt want to use inbuilt function :
def permute(result,input)
if(input.length == 0)
return
end
if(input.length == 1)
puts result + input[0]
return
end
if(input.length == 2)
puts result + input[0] + input[1]
puts result + input[1] + input[0]
return
end
(0...input.length).step(1).each do |i|
firstpart = result+input[i]
secondpart = (i > 0 ? input[0..(i-1)] : '') + (input[(i+1)..-1] || '')
permute(firstpart,secondpart)
end
end
permute('',gets.chomp)
One line:
p "abc".chars.permutation.map &:join
Sample output:
["abc", "acb", "bac", "bca", "cab", "cba"]
p is optional
string could be a variable instead
chars is pretty quick, it separates the string into an array of single characters
map has tons of cool applications,it takes a object, and returns it after the block is done, in this case the operation join
&:join could be replaced with { |i| i.join } like this:
p "abc".chars.permutation.map{ |i| i.join }
If anyone wants to have the code for this using basic algorithms, here is how you do it-
$count = 0
def permute(permuted_string, original_string, done_array)
if permuted_string.length == original_string.length
$count = $count+1
puts "#{$count} #{permuted_string}"
else
(0..original_string.length-1).each do |i|
if !done_array[i]
done_array[i] = true
permute(permuted_string+original_string[i], original_string, done_array)
done_array[i] = false
end
end
end
end
puts "Please enter the string for permutations"
input = gets.chomp
done_array = Array.new(input.length, false)
permute("", input, done_array)
ruby
i have the following
p = 0
[s1.size,s2.size].max.times { |c| if s1[c] == s2[c]; p = c; else break; end };
matched_part = s1[0..p]
but i dont know how i can this for multiple strings (more than 2) at the same time.
Alright, how's this?
class String
def self.overlap(s1,s2,*strings)
strings += [s2]
strings.min { |s| s.size }.size.times do |n|
return s1[0,n] unless strings.all? { |string| s1[n]==string[n] }
end
s1
end
end
class String
def self.overlap(first,second,*others)
s1 = first
others = [second] + others
others.each do |s2|
p = 0
s1.length.times { |c| if s1[c] == s2[c] then p = c else break end }
s1 = s1[0..p]
end
s1
end
end
puts String.overlap "marry had a little lamb", "marry had a bug dog", "marry had a cat", "marry had a bird OUT:", "marry had something" #=> marry had
In one line:
strings[0].slice(0,(0...strings[0].size).find {|i| strings.map {|s| s[i..i]}.uniq.size > 1})