I am trying to solve the following:
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.
Here is what I have, the idea here being the 13 and 1(right after it) get deleted and then the remaining numbers are summed. The issue I have is the delete portion, it's not actually deleting anything. Is this a syntax issue?
x = [1,2,2,1,13,1]
def sum13(nums):
for i in nums:
if i == 13:
del nums[i:i+1]
return sum(nums)
print(sum13(x))
20 <-- should be 6
Your problem is with your index. i is the number in the list, not the index.
Here's a way to solve your problem:
x = [1,2,2,1,13,1]
def sum13(nums):
for i, num in enumerate(nums):
if num == 13:
del nums[i:i+2] # This removes the index i and the index i+1
return sum(nums)
print(sum13(x))
>>> 6
EDIT:
As Thierry Lathuille mentioned in the comments, this doesn't adequately account for the case where you have repeated '13's. Assuming you want this behavior, here's a way you can do that:
def sum13(nums):
for i, num in enumerate(nums):
if num == 13:
stop_cut = i + 1
while nums[stop_cut] == 13:
stop_cut += 1
del nums[i:stop_cut+1]
return sum(nums)
Here's example with recurrent function. As longest as there's 13 in list we sum everything that's before it and sum13 everything that's after that 13.
x = [1,2,2,1,13,1]
def sum13(nums, first_call=False):
if not first_call and nums[0] != 13:
nums = nums[1:]
if 13 in nums:
return sum(nums[:nums.index(13)]) + sum13(nums[nums.index(13)+1:])
return sum(nums)
print(sum13(x, True)) # -> 6
Note that this solution works with neighboring 13s.
x = [13, 13, 1]
print(sum13(x, True)) # -> 0
As long as you are looping through the list, just keep a running sum and a record of the previous value. If i is not 13 and the previous was not 13 add to the sum No need to modify the list passed in.
def sum13(nums):
sum = 0
last = None
for i in nums:
if i != 13 and last != 13:
sum += i
last = i
return sum
One issue is that you are using your list element value as your index. Here's a solution using a generator. First identify index of values to ignore, then create a new list excluding those values.
x = [1,2,2,1,13,1]
def sum13(nums):
def filter13(nums):
for n, i in enumerate(nums):
if i == 13:
yield n
yield n + 1
bad_ix = set(filter13(nums))
new_nums = [x for n, x in enumerate(nums) if n not in bad_ix]
return sum(new_nums)
sum13(x)
Related
def find_even_index(arr):
for a in arr:
b = arr.index(a)
if sum(arr[b+1:]) == sum(arr[:b]):
return b
return -1
find_even_index([20,10,30,10,10,15,35])
>>> -1
My code works for all type of data except when it encounters a same digit before or after the number. The index does not change for other 10. Why?
Just writing out the solution that #Barmar is suggesting in his comments (+1):
def find_even_index(array):
for index in range(len(array)):
if sum(array[:index]) == sum(array[index + 1:]):
return index
return -1
print(find_even_index([20, 10, 30, 10, 10, 15, 35]))
Alternatively, if we wanted to avoid so many calls to sum(), and make good use of enumerate(), we could try:
def find_even_index(array):
total = sum(array)
partial_sum = 0
for index, number in enumerate(array):
if total - partial_sum == number:
return index
partial_sum += number * 2
return -1
The list.index() function will only return the index of the specified object closest to the start of the list. You can instead use enumerate to iterate through the list alongside each object's index:
def find_even_index(arr):
for i, a in enumerate(arr): # For index, number in arr
b = i
if sum(arr[b+1:]) == sum(arr[:b]):
return b
return -1
print(find_even_index([20,10,30,10,10,15,35]))
Output:
3
Given a list of integers and number, I want to find the sum of all numbers in the list such that numbers and before and after a given number are not added. The given number should also be excluded from the numbers used for the final sum.
Examples:
mylist=[1,2,3,4]
number=2
#output is 4
mylist=[1,2,2,3,5,4,2,2,1,2]
number=2
#output is 5
mylist=[1,7,3,4,1,7,10,5]
number=7
#output is 9
mylist=[1,2,1,2]
number=2
#output is 0
In the first example, only the number 4 is not adjacent to the number 2. Thus the sum is 4. In the last example, no numbers meet the criteria so the sum is 0.
This is what I tried:
def add(list1,num):
for i,v in enumerate(list1):
if v==num:
del list1[i-1:i+2]
print list1
add([1,7,3,4,1,7,10,5],7)
However, my code only works for first and third example.
I worked through your code and here is a working solution:
def check_around(array, index, num):
return True if array[index - 1] != num and array[index + 1] != num else False
def get_result(array, num):
arr = []
for i, number in enumerate(array):
if number != num:
if i == 0 and array[1] != num: # Beginning of list
arr.append(number)
elif (i > 0 and i < len(array) - 1) and check_around(array, i, num): # Middle of list
arr.append(number)
elif i == len(array) - 1 and array[i-1] != num: # End of list
arr.append(number)
return arr
test = [([1,2,3,4], 2),
([1,2,2,3,5,4,2,2,1,2], 2),
([1,7,3,4,1,7,10,5], 7),
([1,2,1,2], 2)]
for (arr, num) in test:
res = get_result(arr, num)
print(f'output is {sum(res)}')
#output is 4
#output is 5
#output is 9
#output is 0
The idea is to create a temp array that saves items that do belong in the summation. Otherwise, we ignore them.
I tried all the tests you gave and it seems to be working fine. Hope this helps.
Get the indexes of the element into a list. +1 and -1 to those will give you indexes of 'before' and 'after' elements. Then take the sum avoiding elements in all these indexes.
list=[1,2,2,3,5,4,2,2,1,2]
number=2
#get all indexes of that number
list_of_indexes=[i for i,x in enumerate(list) if x==number]
#no need to remove -1 if there b'coz we are going to enumerate over 'list'
before_indexes=[i-1 for i in list_of_indexes]
#no need to remove len(list) index if present
after_indexes=[i+1 for i in list_of_indexes]
#might contain duplicate values but no problem
all_indexes_to_avoid=list_of_indexes+before_indexes+after_indexes
sum=sum([x for i,x in enumerate(list) if i not in all_indexes_to_avoid ])
print(sum)
Output
5
Why not just use a if statement and generate a new list instead of removing from the list?
def add(list,num):
j=0
new_list=[]
for i in range(len(list)):
if (i<len(list)-1 and list[i+1]==num) or list[i]==num or list[j]==num:
pass
else:
new_list.append(list[i])
j=i
print(sum(new_list))
print(new_list)
return sum
add([1,2,3,4],2)
add([1,2,2,3,5,4,2,2,1,2],2)
add([1,7,3,4,1,7,10,5],7)
add([1,2,1,2],2)
OUTPUT
4
[4]
5
[5]
9
[4, 5]
0
[]
In my program I need to put a while function which sums this list until a particular number is found:
[5,8,1,999,7,5]
The output is supposed to be 14, because it sums 5+8+1 and stops when it finds 999.
My idea looks like:
def mentre(llista):
while llista != 999:
solution = sum(llista)
return solution
Use the iter-function:
>>> l = [5,8,1,999,7,5]
>>> sum(iter(iter(l).next, 999))
14
iter calls the first argument, until the second argument is found. So all numbers are summed up, till 999 is found.
Since you mention using a while loop, you could try a generator-based approach using itertools.takewhile:
>>> from itertools import takewhile
>>> l = [5,8,1,999,7,5]
>>> sum(takewhile(lambda a: a != 999, l))
14
The generator consumes from the list l as long as the predicate (a != 999) is true, and these values are summed. The predicate can be anything you like here (like a normal while loop), e.g. you could sum the list while the values are less than 500.
An example of explicitly using a while loop would be as follows:
def sum_until_found(lst, num):
index = 0
res = 0
if num in lst:
while index < lst.index(num):
res += lst[index]
index += 1
else:
return "The number is not in the list!"
return res
Another possible way is:
def sum_until_found(lst, num):
index = 0
res = 0
found = False
if num in lst:
while not found:
res += lst[index]
index += 1
if lst[index] == num:
found = True
else:
return "The number is not in the list!"
return res
There's many ways of doing this without using a while loop, one of which is using recursion:
def sum_until_found_3(lst, num, res=0):
if num in lst:
if lst[0] == num:
return res
else:
return sum_until_found_3(lst[1:], num, res + lst[0])
else:
return "The number is not in the list!"
Finally, an even simpler solution:
def sum_until_found(lst, num):
if num in lst:
return sum(lst[:lst.index(num)])
else:
return "The number is not in the list!"
Use index and slice
def mentre(llista):
solution = sum(lista[:lista.index(999)])
return solution
Demo
>>> lista = [5,8,1,999,7,5]
>>> sum(lista[:lista.index(999)])
14
def is_prime(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
my_list = is_prime(18)
def prime(x):
my_list2 = []
for number in my_list:
if number <= 2:
my_list2.append(number)
else:
count = 2
while count < number:
if number % count == 0:
break
else:
my_list2.append(number)
count += 1
return my_list2
print prime(18)
Just started out with Python. I have a very simple question.
This prints: [9, 3, 2].
Can someone please tell me why the loop inside my else stops at count = 2? In other words, the loop inside my loop doesn't seem to loop. If I can get my loop to work, hopefully this should print [2, 3]. Any insight is appreciated!
Assuming that my_list2 (not a very nice name for a list) is supposed to contain only the primes from my_list, you need to change your logic a little bit. At the moment, 9 is being added to the list because 9 % 2 != 0. Then 9 % 3 is tested and the loop breaks but 9 has already been added to the list.
You need to ensure that each number has no factors before adding it to the list.
There are much neater ways to do this but they involve things that you may potentially find confusing if you're new to python. This way is pretty close to your original attempt. Note that I've changed your variable names! I have also made use of the x that you are passing to get_prime_factors (in your question you were passing it to the function but not using it). Instead of using the global my_list I have called the function get_factors from within get_prime_factors. Alternatively you could pass in a list - I have shown the changes this would require in comments.
def get_factors(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
# Passing in the number # Passing in a list instead
def get_prime_factors(x): # get_prime_factors(factors):
prime_factors = []
for number in get_factors(x): # for number in factors:
if number <= 2:
prime_factors.append(number)
else:
count = 2
prime = True
while count < number:
if number % count == 0:
prime = False
count += 1
if prime:
prime_factors.append(number)
return prime_factors
print get_prime_factors(18)
output:
[3, 2]
Just to give you a taste of some of the more advanced ways you could go about doing this, get_prime_factors could be reduced to something like this:
def get_prime_factors(x):
prime_factors = []
for n in get_factors(x):
if n <= 2 or all(n % count != 0 for count in xrange(2, n)):
prime_factors.append(n)
return prime_factors
all is a built-in function which would be very useful here. It returns true if everything it iterates through is true. xrange (range on python 3) allows you to iterate through a list of values without manually specifying a counter. You could go further than this too:
def get_prime_factors(x):
return [n for n in get_factors(x) if n <= 2 or all(n % c != 0 for c in xrange(2, n))]
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)
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
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).
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
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
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).
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)
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.