Skip to content
Advertisement

Python sum of number in array, ignoring sections of specific numbers

I am very new to Python and have been going through multiple tutorials to get better.

I have straggled with one difficult problem and found a solution. But it feels, works very newbie like. I think that I have tailored it to answer the specific question.

So the question is:

SUMMER OF ’69: Return the sum of the numbers in the array, except ignore sections of numbers starting with a 6 and extending to the next 9 (every 6 will be followed by at least one 9). Return 0 for no numbers.

summer_69([1, 3, 5]) --> 9
summer_69([4, 5, 6, 7, 8, 9]) --> 9
summer_69([2, 1, 6, 9, 11]) --> 14

My code to solve this is:

def summer_69(arr):
    list1 = arr
    summ = int()
    for i in range(0, len(arr)):
        if 6 in list1:
            listOfRange = range(list1.index(6), list1.index(9) + 1)
            for index in listOfRange:
                    print(listOfRange)
                    arr[index] = 0
            if 6 != arr[i]:
                summ += arr[i]
            else:
                continue
        else:
            summ += arr[i]
    return summ

It is a very basic problem and I am very alerted that I have struggled with something like this already.

Advertisement

Answer

Short O(n) solution using an iterator and the in operator to search for (and thereby skip to) the 9 following each 6:

def summer_69(lst):
    it = iter(lst)
    return sum(x for x in it
               if x != 6 or 9 not in it)

Less dense version:

def summer_69(lst):
    it = iter(lst)
    total = 0
    for x in it:
        if x == 6:
            9 in it
        else:
            total += x
    return total

Correctness check (random test cases) and benchmark (with [1] * 5000 + [6, 9] * 2500) along with the accepted answer’s solution (which takes O(n2)):

30 out of 30 tests correct

303045 us  303714 us  304335 us  306007 us  309986 us  summer_69_Accepted
   444 us     446 us     464 us     478 us     527 us  summer_69_Kelly1
   442 us     448 us     453 us     465 us     500 us  summer_69_Kelly2

Code (Try it online!):

from timeit import repeat

def summer_69_Accepted(lst):
    copyoflist = lst[:] # makes shallow copy of list
    while True:
        if 6 not in copyoflist:
            return sum(copyoflist)

        indexof6 = copyoflist.index(6)
        indexof9 = copyoflist.index(9, indexof6+1) # begin search for 9 after 6
        del copyoflist[indexof6:indexof9+1] 

def summer_69_Kelly1(lst):
    it = iter(lst)
    return sum(x for x in it
               if x != 6 or 9 not in it)

def summer_69_Kelly2(lst):
    it = iter(lst)
    total = 0
    for x in it:
        if x == 6:
            9 in it
        else:
            total += x
    return total

funcs = summer_69_Accepted, summer_69_Kelly1, summer_69_Kelly2

from random import randrange, choices

def testcase():
    def others():
        return choices([0, 1, 2, 3, 4, 5, 7, 8], k=randrange(10))
    lst = others()
    for _ in range(10):
        lst += [6, *others(), 9, *others()]
    return lst

tests = correct = 0
for _ in range(10):
    lst = testcase()
    expect = funcs[0](lst.copy())
    for func in funcs:
        result = func(lst.copy())
        correct += result == expect
        tests += 1
print(correct, 'out of', tests, 'tests correct')
print()

lst = [1] * 5000 + [6, 9] * 2500
for func in funcs:
    times = repeat(lambda: func(lst), number=1)
    print(*('%6d us ' % (t * 1e6) for t in sorted(times)), func.__name__)
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement