2

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.

0

3 Answers 3

2

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]
Sign up to request clarification or add additional context in comments.

Comments

0

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 (e.g., "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.

4 Comments

Manipulate the string directly works, however I receive this error rb:60:in block in describe: Expected: "SOS", instead got: nil (Test::Error) I have added SOS to the dictionary and paired with '...---..." but it still returns nil
What is not clear in "dividing into an array" is: you .split your string morse into an array of single morse word, then iterate over the single word, then I don't understand exactly the next iteration when you .join the value of MORSE_TO_ALPHA.
Floors, I apologize for not replying to your comments earlier. I somehow missed them. It’s late now so I’ll look into the problems you mention tomorrow.
Thank you Cary, I have actually managed to get past the issue by inserting the "SOS" in the dictionary manually and added an if statement just to ensure I could pass the test, and incurred in another error using the different versions of your code as it does not encode back the punctuation (".,!?").
0

assuming: arr = 'a b c 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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.