1

I have the following code, which translates the input string into morse code. My code runs through every letter in the string and then through every character in the alphabet. This is very inefficient, because what if I was reading from a very large file, instead of a small alphabet string. Is there any way that I could improve my code, Maybe using the module re, to match my string with the morse code characters?

morse_alphabet = ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.."
ALPHABET = "abcdefghijklmnopqrstuvwxyz"
morse_letters = morse_alphabet.split(" ")
result = []
count_character = 0


def t(code):

    for character in code:
        count_letter = 0

        for letter in ALPHABET:
            lower_character = code[count_character].lower()
            lower_letter = letter.lower()

            if lower_character == lower_letter:

                result.append(morse_letters[count_letter])

            count_letter += 1

        count_character += 1

    return result
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Jacob Worldly
  • 96
  • 1
  • 2
  • 6

7 Answers7

6

You can use string.ascii_lowercase together with zip() to make a dictionary instead:

import string
morse_alphabet = ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.."
morse_letters = dict(zip(string.ascii_lowercase, morse_alphabet.split()))

def t(code):
    return filter(None, (morse_letters.get(c.lower()) for c in code))

The t function is reduced to a filter() and a generator expression looping over each character in the input code.

The morse_letters dictionary now makes for a very fast lookup of codes, the filter() removes the None results for anything that isn't a letter.

Result:

>>> t('S.O.S.')
['...', '---', '...']
>>> t('Stack Overflow')
['...', '-', '.-', '-.-.', '-.-', '---', '...-', '.', '.-.', '..-.', '.-..', '---', '.--']
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2

Use a dictionary. Assign a dict-key for each letter, then let this have as its value the respective morse-code.

Example - assign morse code for each letter:

morse = {}
morse["a"] = ".-"
morse["b"] = "-..."
#...

Recall the morse code for a letter:

morse_for_a = morse["a"]

The time of a dict-lookup is not affected by the length/size of the dictionary - it is O(1). See this answer.

Community
  • 1
  • 1
poplitea
  • 3,585
  • 1
  • 25
  • 39
1

What I would do is create a dictionary using the letter as the key and the morse code equivalent as the value. Then you can simply loop through the String you are converting and assign the correct value immediately.

thedan
  • 1,230
  • 2
  • 9
  • 13
  • What If i had more general example, where I was reading from a file? – Jacob Worldly Dec 06 '12 at 23:07
  • Do you mean if the String you are reading comes from a file? The same principle would apply. As you receive each character, use the dictionary to transform it to the morse code version and save it. – thedan Dec 06 '12 at 23:11
1

You could use a dictionary, like so:

morse_alphabet = ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.."
ALPHABET = "abcdefghijklmnopqrstuvwxyz"
morse_letters = morse_alphabet.split(' ')
char_to_morse = dict(zip(ALPHABET, morse_letters))

def t(code):
    result = []
    for char in code:
        result.append(char_to_morse[char.lower()])
    return result

print t('abc')

Basically, you would use a dictionary whenever you have a one-to-one mapping between two things (in this case, alphabetic characters to morse code).

Michael0x2a
  • 58,192
  • 30
  • 175
  • 224
0

You could use a dict with defaults - so if a character exists, return that - otherwise it returns the original character...

morse_alphabet = ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.."
ALPHABET = "abcdefghijklmnopqrstuvwxyz"

lookup = dict(zip(ALPHABET, morse_alphabet.split()))
>>> from pprint import pprint
>>> pprint(lookup)
{'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': '--..'}

s = 'sos'
print ''.join(lookup.get(ch, ch) for ch in s)
'...---...'
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
0

Do as little as possible "by hand". Looking up a code in a dict is much faster than using a for loop "manually". Also, you're calling lower() for the alfabet letters, even though you know that they're already lowercase. Calling it once on the entire string, just te be sure, is good. Calling it once for every letter is slow without a good reason.

Bas Wijnen
  • 1,288
  • 1
  • 8
  • 17
0

Here's an approach using ascii codes:

morse_alphabet = ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --..".split(" ")
CHAR_OFFSET = 97 # ord(a) = 97, i.e. a is 97 in ascii

def string_to_morse_code(string):
  morse_code = []
  for char in string.lower():
    try:
      morse_code.append( morse_alphabet[ ord(char) - CHAR_OFFSET] )
    except IndexError:
      continue # ignore any chars we don't understand

  return ' '.join(morse_code)

print string_to_morse_code("Help!!!")

This returns:

.... . .-.. .--.
Rachel Sanders
  • 5,734
  • 1
  • 27
  • 36