Problem

Task from CodingBat:

Return the sum of the numbers in the array, returning 0 for an empty array. Except the number 13 is very unlucky, so it does not count and numbers that come immediately after a 13 also do not count.

My original answer to the problem:

```
def sum13(nums):
sum = 0
for idx,val in enumerate(nums):
if val == 13 or (idx != 0 and nums[idx-1] == 13):
pass
else:
sum = sum + val
return sum
```

Doing this with list comprehension, I came up with

```
return sum([x if x!=13 and nums[idx-1 if idx >0 else 0] !=13 else 0 for idx,x in enumerate(nums)])
```

Is there a way to make this cleaner?

Solution

For the record, I think your original answer is quite clean and readable. My only suggestion would be to consider using `if not (predicate): (do something)`

, as opposed to `if (predicate): pass; else: (do something)`

:

```
def sum13(nums):
sum = 0
for idx,val in enumerate(nums):
if not (val == 13 or (idx != 0 and nums[idx-1] == 13)):
sum += val
return sum
```

I like @Josay’s suggestion of iterating over pairs of consecutive items. The easiest way to do this is by `zip`

ping the list with the list starting from index 1 — i.e., `zip(L, L[1:])`

. From there, it’s just a matter of taking the second item of each pair, unless either of the items == 13. In order to consider the very first item in the list, we’ll prepend `0`

onto the beginning of the list, so that the first pair is `[0, first-item]`

. In other words, we are going to `zip`

together `[0] + L`

(the list with 0 prepended) and `L`

(the list itself). Here are two slightly different versions of this approach:

**Version 1, which is more similar to your original answer:**

```
def sum13(nums):
sum = 0
for first, second in zip([0] + nums, nums):
if not 13 in (first, second):
sum += second
return sum
```

**Version 2, a functional approach using a list comprehension**:

```
def sum13(nums):
pairs = zip([0] + nums, nums)
allowed = lambda x, y: 13 not in (x, y) # not 13 or following a 13
return sum(y for x, y in pairs if allowed(x, y))
```

EDIT: As pointed out by an anonymous user, my first version did not skip numbers that follow an even number of 13’s.

Use an iterator. While you `for`

loop over an iterator you can skip items with `next`

.

```
def lucky_nums(nums):
nums = iter(nums)
for i in nums:
if i == 13:
while next(nums) == 13:
pass
else:
yield i
print sum(lucky_nums([12,13,14,15]))
```

It’s a little “unclean” checking the previous element each time. You can maintain the loop index yourself to avoid this:

```
def sum13(nums):
sum = i = 0
while i < len(nums):
if nums[i] == 13:
i += 2 # Exclude this element, and the next one too.
else:
sum += nums[i]
i += 1
return sum
```

This is similar to the iterator/generator answer.

A few simple comments about your original code : you could rewrite `if A: pass else do_stuff()`

without the `pass`

just writing `if not A: do_stuff()`

. In your case, using De Morgan’s laws, your code becomes :

```
def sum13(nums):
sum = 0
for idx,val in enumerate(nums):
if val != 13 and (idx == 0 or nums[idx-1] != 13):
sum = sum + val
return sum
```

Please note that you have different ways of avoiding accessing the array using indices :

- Save previous item

For instance :

```
def sum13(nums):
sum = 0
prev = None # or any value different from 13
for val in nums:
if val != 13 and prev != 13:
sum = sum + val
prev = val
return sum
```

- Iterate over consecutive arrays (cf https://stackoverflow.com/questions/21303224/iterate-over-all-pairs-of-consecutive-items-from-a-given-list )

Now, a quick comment about your new code : you are summin `x if condition else 0`

to sum all values matching the condition. You could just use `if`

in your list comprehension to filter out elements you don’t want.

```
def sum13(nums):
return sum([x if x!=13 and nums[idx-1 if idx >0 else 0] !=13 else 0 for idx,x in enumerate(nums)])
```

becomes :

```
def sum13(nums):
return sum([x for idx,x in enumerate(nums) if x!=13 and nums[idx-1 if idx >0 else 0] !=13])
```

Also, your code creates a temporary list which is not really required. You could simply write :

```
def sum13(nums):
return sum(x for idx,x in enumerate(nums) if x!=13 and nums[idx-1 if idx >0 else 0] !=13)
```

*Now it seems like an other answer has been given so I don’t have much to say.*

Noting your initial response to the problem

```
def sum13(nums):
sum = 0
for idx,val in enumerate(nums):
if val == 13 or (idx != 0 and nums[idx-1] == 13):
pass
else:
sum = sum + val
return sum
```

you really should write it like this

```
def sum13(nums):
sum = 0
for idx,val in enumerate(nums):
if not(val == 13 or (idx != 0 and nums[idx-1] == 13)):
sum = sum + val
return sum
```

there is no reason to add an extra block to an if statement if you don’t have to, I know that a lot of people don’t like the negatives, but if it is writing a negative if statement or writing an empty if statement, you should write the negative if statement, in this case it is straight to the point