0

I have a function in which I would like to detect the first occurrence of any letter (given a group of letters) within a string and return the index of the letter(see below).

Time is critical so I am thinking of using a try/except method (see LetterDetect below).

Knowing that the try statement will fail most of the time, is this a bad practice? Secondly Would this be more efficient (time-wise) than checking every dictionary entry for the occurrence of each letter (as in LetterDetect2)?

Take the following function which looks:

def LetterDetect(s, letters):
    Dct = {}
    for l in letters:
        Dct[ord(l)] = 0

    for i in range(0, length(s)):
        try:
            Dct[ord(s[i])] +=1
            return i
        except:
            pass

Versus:

def LetterDetect2(s, letters):
    Dct = {}
    for l in letters:
        Dct[ord(l)] = 0

    for i in range(0, length(s)):
       if ord(s[i]) in Dct:
            return i

LetterDetect("test", "abcdt")
LetterDetect2("test", "abcdt")

I appreciate any help, I am new to coding and Python. Thanks!

DannyMoshe
  • 6,023
  • 4
  • 31
  • 53
  • I would say that having a statement that mostly fails is bad practice. It isn't very readable, and error-handling is a relatively expensive form of control flow. – John Coleman Jun 22 '16 at 03:31

2 Answers2

4

Using a dictionary seems like an odd way to solve this problem. Is there some specific reason you're using that?

The string method .find() https://docs.python.org/2/library/stdtypes.html#str.find seems like a much better solution:

def LetterDetect(s, letters)
    for l in letters:
        position = s.find(l)
        if position != -1:
            return position
    return None
John Gordon
  • 29,573
  • 7
  • 33
  • 58
  • Wouldn't using a dictionary be more efficient since rather than comparing against every letter in the string the code would check if it matches an existing key (referring to the first LetterDetect function)? Or am I misunderstanding how a dictionary is checked for an existing key. – DannyMoshe Jun 22 '16 at 04:08
  • 1
    @DannyMoshe Is your code trying to count the number of occurrences of various characters? In such cases use `Counter`: `from collections import Counter; Counter(ord(c) for c in the_text)`. – Bakuriu Jun 22 '16 at 10:28
  • 1
    @DannyMoshe Dictionary lookup might be more efficient than linear string checking, _assuming the dictionary is already built_, which it is not in your solution. – John Gordon Jun 22 '16 at 15:40
  • @JohnGordon I built the dictionary for the characters in "letters". Then I'm checking characters in "s" one by one against the dictionary. This would return an error for not-found entries which I thought might be more efficient than a linear string check (an O(n*n) operation in this case). But sounds like based on what you have said the try/except will be less efficient. – DannyMoshe Jun 22 '16 at 16:07
  • 1
    @DannyMoshe Your solution is doing double the work: building the dictionary (which requires looking at each individual character in `letters`), _then_ looking up in the dict. – John Gordon Jun 22 '16 at 16:18
  • @JohnGordon But wouldn't the worst case of that be an O(n+n) operation versus an O(n*n) operation? I say O(n*n) since s.find(l) will in the worst case search for every character in "letters" in every character of "s"? – DannyMoshe Jun 22 '16 at 16:34
  • @DannyMoshe I see what you're getting at. I've never done heavy analysis of algorithms so I don't know the real answer. My gut says your solution is slower, but I could be wrong. – John Gordon Jun 22 '16 at 16:43
3

In addition to the basic problems with your design that John Gordon pointed out, I would like to respond directly to the question:

  1. Using try/catch to achieve ordinary flow control is an abuse of its purpose. I can predict several ways this might bite you (the debugger might stop you on the exception, a future programmer might "correct" your code) but the basic rule is, use language features as they were designed.
  2. As a practical matter, a try/catch will tend to be slow. The language runtime has to get involved and do all sorts of fancy things, none of which you actually need.
  3. Exceptions should be, well, exceptional.
Michael Lorton
  • 43,060
  • 26
  • 103
  • 144