12

I'm new to programming and I'm trying to do the codingbat.com problems to start. I came across this problem:

Given an array calculate the sum except when there is a 13 in the array. If there is a 13 in the array, skip the 13 and the number immediately following it. For example [1,2,13,5,1] should yield 4 (since the 13 and the 5s are skipped).

This is what I have so far. My problem is that I don't know what to do when there are multiple 13s...And I would like to learn coding efficiently. Can you guys help? (I'm using python 3.2) Thanks!

def pos(nums):
    for i in nums:
        if i == 13:
            return nums.index(13)
    return False

def sum13(lis):
    if pos(lis)!= False:
        return sum(lis[:pos(lis)])+sum(lis[pos(lis)+1:])
    else:
        return sum(lis)
5
  • 1
    Your example should really yield 4, right? 1+2+1 = 4. Commented Jun 16, 2012 at 1:09
  • 2
    @WillBuddha I think the behavior of consecutive 13s is a little ambiguous, actually. Should a 13 skip the subsequent 13's effect? Commented Jun 16, 2012 at 1:30
  • Let's assume a 13 doesn't skip the effect of a consecutive 13 so that [13,13,1,4] yields a 4. Commented Jun 16, 2012 at 1:39
  • if foo != False: is redundant; just use if foo: Commented Jun 16, 2012 at 2:07
  • The answer you accepted works here as well: codingbat.com/prob/p108886 Commented Dec 13, 2016 at 14:17

7 Answers 7

11

One tricky thing to notice is something like this: [1, 13, 13, 2, 3]

You need to skip 2 too

def getSum(l):
    sum = 0
    skip = False
    for i in l:
         if i == 13:
             skip = True
             continue
         if skip:
             skip = False
             continue
         sum += i
    return sum

Explanation:

You go through the items in the list one by one

Each time you

  • First check if it's 13, if it is, then you mark skip as True, so that you can also skip next item.
  • Second, you check if skip is True, if it is, which means it's a item right after 13, so you need to skip this one too, and you also need to set skip back to False so that you don't skip next item.
  • Finally, if it's not either case above, you add the value up to sum
Sign up to request clarification or add additional context in comments.

6 Comments

Can you explain this iteration for a newb like me?
Ah, I didn't realize if skip: implied if skip = True...Thanks!
Ah I like this answer I understand it! (The zip function is too advanced for me right now) thanks again!
elif would be better here than continue
Note to OP: this answer works for this as well: codingbat.com/prob/p108886
|
6

You can use the zip function to loop the values in pairs:

def special_sum(numbers):
    s = 0
    for (prev, current) in zip([None] + numbers[:-1], numbers):
        if prev != 13 and current != 13:
            s += current
    return s

or you can do a oneliner:

def special_sum(numbers):
    return sum(current for (prev, current) in zip([None] + numbers[:-1], numbers)
               if prev != 13 and current != 13)

You can also use iterators:

from itertools import izip, chain
def special_sum(numbers):
    return sum(current for (prev, current) in izip(chain([None], numbers), numbers)
               if prev != 13 and current != 13)

(the first list in the izip is longer than the second, zip and izip ignore the extra values).

2 Comments

Wow Thanks! This one looks like it would work and after a long look I now understand it. Thanks!
This code is very memory inefficient, and will not work with iterators :)
3

Use a while loop to walk through the list, incrementing i manually. On each iteration, if you encounter a 13, increment i twice; otherwise, add the value to a running sum and increment i once.

def skip13s(l):
    i = 0
    s = 0
    while (i < len(l)):
        if l[i] == 13:
            i += 1
        else:
            s += l[i]
        i += 1
    return s

Comments

2

Some FP-style :)

def add_but_skip_13_and_next(acc, x):
    prev, sum_ = acc
    if prev != 13 and x != 13:
        sum_ += x
    return x, sum_

filter_and_sum = lambda l: reduce(add_but_skip_13_and_next, l, (0,0))[1]

>>> print filter_and_sum([13,13,1,4])
4
>>> print filter_and_sum([1,2,13,5,13,13,-9,13,13,13,13,13,1,1])
4

This code works for any iterator, even it not provide the random access (direct indexing) - socket for example :)

Oneliner :)

>>> filter_and_sum = lambda l: reduce(
...     lambda acc, x: (x, acc[1] + (x if x != 13 and acc[0] != 13 else 0)),
...     l, (0,0))[1]
>>> print filter_and_sum([1,2,13,5,13,13,-9,13,13,13,13,13,1,1])
4

Comments

1

I think this is the most compact solution:

def triskaidekaphobicSum(sequence):
    return sum(sequence[i] for i in range(len(sequence))
               if sequence[i] != 13 and (i == 0 or sequence[i-1] != 13))

This uses the builtin sum() function on a generator expression. The generator produces all the elements in the sequence as long as they are not 13, or immediately following a 13. The extra "or" condition is to handle the first item in the sequence (which has no previous item).

Comments

0

You can use while loop to treat multiple 13.

def sum13(lis):
    while pos(lis):
        if pos(lis) == len(lis) - 1:
            lis = lis[:pos(lis)]
        else:
            lis = lis[:pos(lis)]+lis[pos(lis)+1:]

    return sum(lis)

2 Comments

For some reason this didn't work for [13,1,2,13,2,1,13]...It gave 45 as the sum
I think it is because the latest element in the list is 13.So I edited my code.
0
def skipAndAddFun(inputVal, skipList):
   sum = 0
   for i in inputVal:
        if not i in skipList:
            sum += i
    return sum

Usage:

skipAndAddFun([1,2,13,5,1], [13, 5])
4

This simple function will be a generic solution for your question.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.