Alex Rivera | Logout

Avoiding repeat of code after loop?

Asked 2012-06-22T04:01:03.023
15

I often end up writing a bit of code twice when using a loops. For example, while going over the Udacity computer science course, I wrote the code (for a function to find the most sequentially repeated element):

def longest_repetition(l):
    if not l:
        return None
    most_reps = count = 0 
    longest = prv = None
    for i in l:
        if i == prv:
            count += 1
        else:
            if count > most_reps:
                longest = prv
                most_reps = count
            count = 1
        prv = i
    if count > most_reps:
        longest = prv
    return longest

In this case, I'm checking twice if the count is greater than the previously most repeated element. This happens both when the current element is different from the last and when I've reached the end of the list.

I've also run into this a few times when parsing a string character by character. There have also been a few times where it's been up to about 5 lines of code. Is this common, or a result of the way I think/code. What should I do?

edit: Similarly, in a contrived string splitting example:

def split_by(string, delimeter):
    rtn = []
    tmp = ''
    for i in string:
        if i == delimeter:
            if tmp != '':
                rtn.append(tmp)
                tmp = ''
        else:
            tmp += i
    if tmp != '':
        rtn.append(tmp)
    return rtn

edit: The exam this was from was written for students of the course who are not expected to have any outside knowledge of Python; only what was taught in the previous units. Although I do have prior experience in Python, I'm trying to adhere to these restrictions to get the most of the course. Things like str.split, lists, and a lot of the fundamentals of Python were taught, but nothing yet on imports - especially not things like groupby. That being said, how should it be written without any of the language features

Edit
Report

1 Answer

2

I think there are three general approaches that could help you avoid repeating code at the end of the loop. For all three I'm going to use an example problem slightly different from your own, counting words in a string. Here's a "default" version that, like your code, repeats some logic at the end of the loop:

from collections import Counter

def countWords0(text):
    counts = Counter()
    word = ""

    for c in text.lower():
        if c not in "abcdefghijklmnopqrstuvwxyz'-":
            if word:
                counts[word] += 1
            word = ""
        else:
            word += c

    if word:
        counts[word] += 1 # repeated code at end of loop

    return counts

The first approach is to do (some of) the "end of subsequence" processing after every character, so that the bookkeeping is correct if the sequence ends immediately after that character. In your example, you could eliminate the "else" condition on your and run the code within it every time. (This is sergerg's answer.)

This may not be easy for some kinds of checks though. For counting words, you need to add some extra logic to avoid accumulating cruft from the "partial" subsequences you process. Here's code that does that:

def countWords1(text):
    counts = Counter()
    word = ""

    for c in text.lower():
        if c not in "abcdefghijklmnopqrstuvwxyz'-":
            word = ""
        else:
            if word:
                counts[word] -= 1 # new extra logic
            word += c
            counts[word] += 1 # this line was moved from above

    return counts + Counter() # more new stuff, to remove crufty zero-count items

The second option would be to append a sentinel value to the end of the sequence which will trigger the desired "end of subsequence" behavior. This can be tricky if you need to avoid the sentinel contaminating your data (especially for things like numbers). For your longest consecutive

answered 2012-06-22T06:23:52.430

Your Answer