Jacob Worldly
Jacob Worldly

Reputation: 96

How to improve efficiency in loops?

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

Upvotes: 1

Views: 247

Answers (7)

Michael0x2a
Michael0x2a

Reputation: 64068

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).

Upvotes: 1

Rachel Sanders
Rachel Sanders

Reputation: 5874

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:

.... . .-.. .--.

Upvotes: 0

thedan
thedan

Reputation: 1240

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.

Upvotes: 1

poplitea
poplitea

Reputation: 3737

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.

Upvotes: 2

Bas Wijnen
Bas Wijnen

Reputation: 1328

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.

Upvotes: 0

Martijn Pieters
Martijn Pieters

Reputation: 1121972

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')
['...', '-', '.-', '-.-.', '-.-', '---', '...-', '.', '.-.', '..-.', '.-..', '---', '.--']

Upvotes: 6

Jon Clements
Jon Clements

Reputation: 142156

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)
'...---...'

Upvotes: 0

Related Questions