I would like someone to clarify how can I possibly iterating over an array, find an exact match in an hash[value], and replace the element in the array with the hash[key].
As example, if I have a morse directory morse_dict = { "a" => ".-","b" => "-...","c" => "-.-.","d" => "-..","e" => ".","f" => "..-.","g" => "--.","h" => "....","i" => "..","j" => ".---","k" => "-.-","l" => ".-..","m" => "--","n" => "-.","o" => "---","p" => ".--.","q" => "--.-","r" => ".-.","s" => "...","t" => "-","u" => "..-","v" => "...-","w" => ".--","x" => "-..-","y" => "-.--","z" => "--.."," " => " ","1" => ".----","2" => "..---","3" => "...--","4" => "....-","5" => ".....","6" => "-....","7" => "--...","8" => "---..","9" => "----.","0" => "-----" }
and I want a method that for a given string in morse code returns a string in regular alphabet. This is the codewars kata .
I am not interested in the solution to the challenge itself, I would like to understand the principle of this.
So far I have thought of proceeding this way:
def morse_code(arr)
arr.split(" ").each {|element|
element.each_char {|char|
(morse_dict.include?(char)) ? (print "true") : (print "false")}
}
end
I only print false, which means that I am not actually looking for match into the hash.
Using Hash#key without replacing the array, rather creating a new one (use map!
for replacement):
array = [1,2,3,4,5]
hash = {a: 4, b: 7, c: 3}
array.map { |el| hash.key(el) }
# => [nil, nil, :c, :a, nil]
You may want to think about using Hash#invert and simply referencing the elements by keys for performance reasons as Hash#key
is O(n)
while Hash#[]
is O(1)
.
array = [1,2,3,4,5]
hash = {a: 4, b: 7, c: 3}
inverted_hash = hash.invert
array.map { |el| inverted_hash[el] }
# => [nil, nil, :c, :a, nil]
assuming: arr = 'abc d'
, which is not an arr, so please make that morse_string
def morse_code(morse_string)
new_elements = []
# iterate over each character in the string,
morse_string.split(" ").each do |element|
if morse_dict[element]
# https://apidock.com/ruby/Array/push
new_elements.push( morse_dict[element] )
else
# whatever you want to do when there is no match
end
end
# re-create the string again, but with braille
# https://apidock.com/ruby/Array/join
new_elements.join(' ')
end
morse_string = 'a b c d'
morse_code(morse_string)
I understand from the kata that letters are to be separated by one space and words by three spaces.
As a first step I will two changes to the hash morse_dict
: remove the key ' '
; and add key-value pairs for some punctuation characters. The space character key is not needed; the need for punctuation codes is discussed in the kata.
PUNCTUATION = { "."=>".-.-.-", ","=>"--..--", "?"=>"..--..", "!"=>"-.-.--" }
ALPHA_TO_MORSE = dict.reject { |k,_| k == " " }.merge(PUNCTUATION)
#=> {"a"=>".-", "b"=>"-...", "c"=>"-.-.", "d"=>"-..", "e"=>".", "f"=>"..-.",
# "g"=>"--.", "h"=>"....", "i"=>"..", "j"=>".---", "k"=>"-.-", "l"=>".-..",
# "m"=>"--", "n"=>"-.", "o"=>"---", "p"=>".--.", "q"=>"--.-", "r"=>".-.",
# "s"=>"...", "t"=>"-", "u"=>"..-", "v"=>"...-", "w"=>".--", "x"=>"-..-",
# "y"=>"-.--", "z"=>"--..", "1"=>".----", "2"=>"..---", "3"=>"...--",
# "4"=>"....-", "5"=>".....", "6"=>"-....", "7"=>"--...", "8"=>"---..",
# "9"=>"----.", "0"=>"-----", "."=>".-.-.-", ","=>"--..--", "?"=>"..--..",
# "!"=>"-.-.--"}
I obtained the Morse codes for the punctuation characters from the Morse Code Wiki . Additional punctuation characters could be added if desired.
The hash ALPHA_TO_MORSE
is used in encoding text. The inverse of this hash is needed for decoding messages in Morse code. Also needed for decoding is the key value pair "...---..."=>"sos"
.
MORSE_TO_ALPHA = ALPHA_TO_MORSE.invert.merge("...---..."=>"sos")
#=> {".-"=>"a", "-..."=>"b", "-.-."=>"c", "-.."=>"d", "."=>"e", "..-."=>"f",
# "--."=>"g", "...."=>"h", ".."=>"i", ".---"=>"j", "-.-"=>"k", ".-.."=>"l",
# "--"=>"m", "-."=>"n", "---"=>"o", ".--."=>"p", "--.-"=>"q", ".-."=>"r",
# "..."=>"s", "-"=>"t", "..-"=>"u", "...-"=>"v", ".--"=>"w", "-..-"=>"x",
# "-.--"=>"y", "--.."=>"z", ".----"=>"1", "..---"=>"2", "...--"=>"3",
# "....-"=>"4", "....."=>"5", "-...."=>"6", "--..."=>"7", "---.."=>"8",
# "----."=>"9", "-----"=>"0", ".-.-.-"=>".", "--..--"=>",",
# "..--.."=>"?", "-.-.--"=>"!""...---..."=>"sos"}
One more hash is needed to deal with cases where the message "sos"
(or "SOS"
--Morse code is case insensitive), or "sos"
followed by a punctuation character (eg, "sos!"
) is to be encoded. 1 See the Wiki.
SOS_WITH_PUNCTUATION = PUNCTUATION.each_with_object({}) { |(k,v),h|
h["sos#{k}"] = "...---... #{v}" }.merge('sos'=>"...---...")
#=> {"sos."=>"...---... .-.-.-", "sos,"=>"...---... --..--",
# "sos?"=>"...---... ..--..", "sos!"=>"...---... -.-.--", "sos"=>"...---..."}
The encoding and decoding methods follow. encode
checks to see if each word in the string is a key in the hash SOS_WITH_PUNCTUATION
. If it is, the value of key is the Morse code for the word; else, the word is divided into letters and each letter is translated into Morse code.
def encode(str)
str.strip.downcase.split.map do |word|
if SOS_WITH_PUNCTUATION.key?(word)
SOS_WITH_PUNCTUATION[word]
else
word.each_char.map { |c| ALPHA_TO_MORSE[c] }.join(' ')
end
end.join (' ')
end
def decode(morse)
morse.strip.split(/ {3}/).map do |word|
word.split.map { |c| MORSE_TO_ALPHA[c] }.join
end.join(' ')
end
We can now try out these two methods.
str = " Is now the time for you, and 007, to send an SOS?"
morse = encode str
#=> ".. ... -. --- .-- - .... . - .. -- . ..-. --- .-. -.-- --- ..- --..-- .- -. -.. ----- ----- --... --..-- - --- ... . -. -.. .- -. ...---... ..--.."
decode morse
#=> "is now the time for you, and 007, to send an sos?"
1 It would be simpler to have a pre-processing step that would convert, say, "sos."
to "sos ."
, but when the resulting Morse code were decoded there would be a space between "sos"
and "."
. I suppose that cryptographers could deal with that, but I've chosen to avoid the insertion of the space.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.