Reputation: 117
I'm trying to make a method that, given a string, replaces every letter with its position in the alphabet.
If anything in the text isn't a letter, I want to ignore it and not return it.
"a" = 1, "b" = 2, etc.
Example
alphabet_position("The sunset sets at twelve o' clock.")
Should return "20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"
(as a string)
I tried this, but it didn't work:
def alphabet_position(text)
alph = ("a".."z").to_a
text = text.split(/./).map {|ch| if ch.in?(alph)
((alph.index[ch]).to_i+1).to_s
else
""
end
}.join(" ").strip
end
Thanks in advance!
Upvotes: 0
Views: 1675
Reputation: 29383
First we can build the translation because Hash lookups are extremely fast:
# alternatively letter_to_number = ('a'..'z').each.with_index(1).to_h
letter_to_number = ('a'..'z').zip(1..26).to_h
#=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6,
# "g"=>7, "h"=>8, "i"=>9, "j"=>10, "k"=>11, "l"=>12,
# "m"=>13, "n"=>14, "o"=>15, "p"=>16, "q"=>17, "r"=>18,
# "s"=>19, "t"=>20, "u"=>21, "v"=>22, "w"=>23, "x"=>24, "y"=>25, "z"=>26}
Then simply swap them out
# ruby >= 2.7
text.downcase.each_char.filter_map {|c| letter_to_number[c] }.join(' ')
# ruby < 2.7
text.downcase.each_char.map {|c| letter_to_number[c] }.compact.join(' ')
#=> "20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11"
Upvotes: 4
Reputation: 110685
def convert(str)
str.downcase.each_char.with_object('') do |c,s|
n = c.ord
if n.between?(97, 122)
s << ' ' unless s.empty?
s << (n-96).to_s
end
end
end
convert "Sunset was at twelve o'clock, somewhere, on some day"
#=> "19 21 14 19 5 20 23 1 19 1 20 20 23 5 12 22 5 15 3 12 15 3 11 19 15 13 5 23 8 5 18 5 15 14 19 15 13 5 4 1 25"
Lady and gentleman, start your engines!
def alphabet_position(text)
text.downcase.split('').map do |letter|
index = ('a'..'z').find_index(letter)
index + 1 if index
end.compact.join(' ')
end
def smnky_1_7(str)
letter_to_number = ('a'..'z').zip(1..26).to_h
str.downcase.each_char.filter_map {|c| letter_to_number[c] }.join(' ')
end
def smnky_pre_1_7(str)
letter_to_number = ('a'..'z').zip(1..26).to_h
str.downcase.each_char.map {|c| letter_to_number[c] }.compact.join(' ')
end
LETTER_TO_NUMBER = ('a'..'z').zip(1..26).to_h
def smnky_pre_w_constant(str)
str.downcase.each_char.map {|c| LETTER_TO_NUMBER[c] }.compact.join(' ')
end
def convert_with_arr(str)
str.downcase.each_char.with_object([]) do |c,arr|
n = c.ord
arr << n - 96 if n.between?(97, 122)
end.join(' ')
end
str = "Sunset was at twelve o'clock, somewhere, on some day"
require 'benchmark'
def run(m, str)
500.times { method(m).call(str) }
end
Benchmark.bm(19) do |x|
x.report("Cary") { run(:convert, str) }
x.report("Tatiana") { run(:alphabet_position, str) }
x.report("smnky 1.7") { run(:smnky_1_7, str) }
x.report("smnky pre 1.7") { run(:smnky_1_7, str) }
x.report("smnky pre w/constant") { run(:smnky_pre_w_constant, str) }
x.report("Cary with arr") { run(:convert_with_arr, str) }
end
user system total real
Cary 0.018610 0.000300 0.018910 ( 0.019135)
Tatiana 0.067738 0.001138 0.068876 ( 0.070317)
smnky 1.7 0.028659 0.001035 0.029694 ( 0.030583)
smnky pre 1.7 0.032050 0.001662 0.033712 ( 0.035089)
smnky pre w/constant 0.013705 0.000323 0.014028 ( 0.014139)
Cary with arr 0.016989 0.000538 0.017527 ( 0.017925)
Upvotes: 2
Reputation: 24
def alphabet_position(text)
text.downcase.split('').map do |letter|
index = ('a'..'z').find_index(letter)
index + 1 if index
end.compact.join(' ')
end
Upvotes: 0
Reputation: 513
Following the answer of @Siim Liiser, also you can use scan method to get letters.
text = "The sunset sets at twelve o' clock."
irb(main):002:0> text.scan(/[a-z]/)
=> ["h", "e", "s", "u", "n", "s", "e", "t", "s", "e", "t", "s", "a", "t", "t", "w", "e", "l", "v", "e", "o", "c", "l", "o", "c", "k"]
As you can see, the letter T is uppercase and are missing, to solve this youy can use downcase before to call the method scan:
irb(main):004:0> text.downcase.scan(/[a-z]/)
=> ["t", "h", "e", "s", "u", "n", "s", "e", "t", "s", "e", "t", "s", "a", "t", "t", "w", "e", "l", "v", "e", "o", "c", "l", "o", "c", "k"]
Upvotes: 0
Reputation: 4348
In order to debug a piece of code, run it line by line. Pretty soon you'll find that:
text = "The sunset sets at twelve o' clock."
text.split(/./) #=> []
It does not do what you think it does.
I think you meant one of those:
text.split('') #=> ["T", "h", "e", " ", ...
text.chars #=> ["T", "h", "e", " ", ...
There are several more bugs but I'll leave those for you to figure out.
Upvotes: 1