Python function with double condition - python

I'd like to create a function that returns the elements of a list on odd positions or the negative elements of a list.
My solution works with the first assertion, but the second generates an AssertionError, because returns [-1, -2, 1] instead of [-1, -2]. Any suggestions?
def solution(input):
output = []
for item in input:
if item < 0:
output.append(item)
elif not item % 2 == 0:
output.append(item)
return output
assert solution([0,1,2,3,4,5]) == [1,3,5]
assert solution([1,-1,2,-2]) == [-1,-2]

You want the numbers on odd positions, but your % check is checking the actual values in the list rather than their positions.
Try using enumerate to get the index alongside the value as you iterate through the list:
def solution(input):
output = []
for ix, item in enumerate(input):
if item < 0 or ix % 2 != 0:
output.append(item)
return output

Also for completeness purpose you may want to consider adding this to your already existing code:
if any(i < 0 for i in output):
return [i for i in output if i < 0]
, since it tests if a negative exists and return only those if so. The answer by HumphreyTriscuit is, however, the better solution from my point of view.

One line to define solution function:
def solution(input):
return [input[pos] for pos in range(len(input)) if not pos %2 == 0 or input[pos] < 0]
print solution([0,1,2,3,4,5,7])
print solution([1,-1,2,-2, -3])

Related

Index value not in list

I need to write code that returns 2 index numbers of an array. The function takes 2 arguments, one is an array and the other is an integer.
I need to check if two of the values inside the array adds up to the integer and using the numbers inside the array only once.
Here is my code:
def func(a,b):
for i in a:
cnt = 0
while cnt < len(a):
if i + a[cnt] == b and i != a[cnt]:
return list([i,a[cnt]])
else:
cnt += 1
print(func([3,7,2,10,20],27))
My output for func([3, 7, 2, 10, 20], 27) is [7, 20].
This code shows that the loop can find the numbers which add up to the integer.
But when I do this:
def func(a,b):
for i in a:
cnt = 0
while cnt < len(a):
if i + a[cnt] == b and i != a[cnt]:
return a.index(i,a[cnt])
else:
cnt += 1
print(func([3,7,2,10,20],27))
I get the Value error: 7 not in list, which clearly is.
I've had this issue working with other exercises as well.
Am I doing something wrong or the index function isn't suppose to be used like that.
What would be an efficient way to return the index numbers without having to write another loop for it?
The second parameter to index that you're passing is actually the starting index on the list in which the search for the element will start (as you can see here). If you remove it, you'll see that it returns the first value you want (but not the second). It is relevant to note that the index method will only ever return the first occurrence of the value.
def func(a,b):
for i in a:
cnt = 0
while cnt < len(a):
if i + a[cnt] == b and i != a[cnt]:
return a.index(i)
else:
cnt += 1
print(func([3,7,2,10,20],27))
>>> 1
This happens because the value you're passing as the starting index (a[cnt]) is greater than the actual index of the number (1).
By removing it, you search through all the list, and find the correct value (remembering that Python uses zero-indexed iterators).
But since you want to return a list with both values, you need to explicitly state you want the index for each, such as:
def func(a,b):
for i in a:
cnt = 0
while cnt < len(a):
if i + a[cnt] == b and i != a[cnt]:
return [a.index(i), a.index(a[cnt])]
else:
cnt += 1
print(func([3,7,2,10,20],27))
>>> [1, 4]
You could achieve the same results using two for loops, however, in a cleaner way (also gave meaningful names to variables):
def find_indices_for_sum(array, sum_value):
for i in array:
for j in array:
if i + j == sum_value and i != j:
return [array.index(i), array.index(j)]
print(find_indices_for_sum([3,7,2,10,20],27))
>>> [1, 4]
If you want to be able to deal with equal numbers, you can change the comparison strategy altogether, using indices instead of values, since the former are unique in a list, but the latter are not. enumerate is a good option here, since it allows to iterate both through index and values at the same time in a clean way.
def find_indices_for_sum(array, sum_value):
for i, value_i in enumerate(array):
for j, value_j in enumerate(array):
if i != j and value_i + value_j == sum_value:
return [i, j]
print(find_indices_for_sum([3,3],6))
>>> [0, 1]

After reversing list elements are changing?

after I reverse my list list elements are changing not reversing properly
here is my first code
def reverse_fib_series(num):
x = []
for i in range(num):
if i == 0:
x.append(0)
elif i == 1:
x.append(1)
else:
x.append(sum(reverse_fib_series(i)[-2:]))
return x
print(reverse_fib_series(11))
it returns [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
if I want to reverse it
def reverse_fib_series(num):
x = []
for i in range(num):
if i == 0:
x.append(0)
elif i == 1:
x.append(1)
else:
x.append(sum(reverse_fib_series(i)[-2:]))
return x[::-1]
print(reverse_fib_series(11))
it returns [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]. I do not know why?
i am trying to solve the following exercise:
"In Fibonacci Numbers, each number progresses as the sum of the two preceding numbers, such as 0,1,1,2,3,5,8, ... In this question you are given a number (0 <N <20). Accordingly, write the program that prints all Fibonacci numbers backwards from the Nth Fibonacci number."
This is happening because you reverse the list in each recursive call, rather than only reversing it once at the end -- so instead of summing the last two elements of the series to get the next element, you're summing the first two elements, which are always 0 and 1. That's why every element of the series after the first two becomes 1. (The list isn't changing when you reverse it at the end, the computation of the series is broken because you're reversing it each time.)
You could write the function so that it builds the series in-place from back to front, or you could fix this by simplifying the loop body to eliminate the unnecessary recursion, but this is a good opportunity to learn the concept of composing two simple things to produce one more complicated thing. :) Rather than trying to do it all at once, take the working (if sub-optimal) function you already have to produce the Fibonacci series, and then reverse it afterwards:
def fib_series(num):
x = []
for i in range(num):
if i == 0:
x.append(0)
elif i == 1:
x.append(1)
else:
x.append(sum(fib_series(i)[-2:]))
return x
def reverse_fib_series(num):
return fib_series(num)[::-1]
Note that your fib_series function can be a little simpler than what you wrote; you don't need to recursively call fib_series to get the last two numbers, because you already have them stored in x:
def fib_series(num):
x = []
for i in range(num):
if i == 0:
x.append(0)
elif i == 1:
x.append(1)
else:
x.append(sum(x[-2:]))
return x
or you could make it a little shorter by writing it as a generator:
def fib_series(num):
x = [0, 1]
x.extend(sum(x[-2::]) for _ in range(num - 2))
return x[:num]
try this code:
def reverse_fib_series(num):
x = []
for i in range(num):
if i == 0:
x.append(0)
elif i == 1:
x.append(1)
else:
x.append(sum(reverse_fib_series(i)[-2:]))
return x
print(reverse_fib_series(11)[::-1])
reverse the return value because you use recursion in the function
Because you are reversing array inside of a recursive function. It adds one number and reverse. And it keeps repeating the process.
This code will hel
def reverse_fib_series(num):
x = []
for i in range(num):
if i == 0:
x.append(0)
elif i == 1:
x.append(1)
else:
x.append(sum(reverse_fib_series(i)[-2:]))
return x
reversed = reverse_fib_series(11)[::-1]
print(reversed)
Just another ways, using [].insert(0, sum())
def reverse_fib_loop(n: int):
lx = []
for i in range(n):
if i > 1:
lx.insert(0, sum(lx[:2]))
else:
lx.insert(0, i)
return lx
def reverse_fib_recursion(size: int):
def wrapped(lx: list, sn: int, n: int):
if n > 0:
lx.insert(0, sn)
sn = sum(lx[:2]) if len(lx) >= 2 else 1
return wrapped(lx, sn, n-1)
return lx
return wrapped([], 0, size)
if __name__ == '__main__':
N = int(input('N='))
print(reverse_fib_loop(N))
print(reverse_fib_recursion(N))

How to see if the list contains consecutive numbers

I want to test if a list contains consecutive integers and no repetition of numbers.
For example, if I have
l = [1, 3, 5, 2, 4, 6]
It should return True.
How should I check if the list contains up to n consecutive numbers without modifying the original list?
I thought about copying the list and removing each number that appears in the original list and if the list is empty then it will return True.
Is there a better way to do this?
For the whole list, it should just be as simple as
sorted(l) == list(range(min(l), max(l)+1))
This preserves the original list, but making a copy (and then sorting) may be expensive if your list is particularly long.
Note that in Python 2 you could simply use the below because range returned a list object. In 3.x and higher the function has been changed to return a range object, so an explicit conversion to list is needed before comparing to sorted(l)
sorted(l) == range(min(l), max(l)+1))
To check if n entries are consecutive and non-repeating, it gets a little more complicated:
def check(n, l):
subs = [l[i:i+n] for i in range(len(l)) if len(l[i:i+n]) == n]
return any([(sorted(sub) in range(min(l), max(l)+1)) for sub in subs])
The first code removes duplicates but keeps order:
from itertools import groupby, count
l = [1,2,4,5,2,1,5,6,5,3,5,5]
def remove_duplicates(values):
output = []
seen = set()
for value in values:
if value not in seen:
output.append(value)
seen.add(value)
return output
l = remove_duplicates(l) # output = [1, 2, 4, 5, 6, 3]
The next set is to identify which ones are in order, taken from here:
def as_range(iterable):
l = list(iterable)
if len(l) > 1:
return '{0}-{1}'.format(l[0], l[-1])
else:
return '{0}'.format(l[0])
l = ','.join(as_range(g) for _, g in groupby(l, key=lambda n, c=count(): n-next(c)))
l outputs as: 1-2,4-6,3
You can customize the functions depending on your output.
We can use known mathematics formula for checking consecutiveness,
Assuming min number always start from 1
sum of consecutive n numbers 1...n = n * (n+1) /2
def check_is_consecutive(l):
maximum = max(l)
if sum(l) == maximum * (maximum+1) /2 :
return True
return False
Once you verify that the list has no duplicates, just compute the sum of the integers between min(l) and max(l):
def check(l):
total = 0
minimum = float('+inf')
maximum = float('-inf')
seen = set()
for n in l:
if n in seen:
return False
seen.add(n)
if n < minimum:
minimum = n
if n > maximum:
maximum = n
total += n
if 2 * total != maximum * (maximum + 1) - minimum * (minimum - 1):
return False
return True
import numpy as np
import pandas as pd
(sum(np.diff(sorted(l)) == 1) >= n) & (all(pd.Series(l).value_counts() == 1))
We test both conditions, first by finding the iterative difference of the sorted list np.diff(sorted(l)) we can test if there are n consecutive integers. Lastly, we test if the value_counts() are all 1, indicating no repeats.
I split your query into two parts part A "list contains up to n consecutive numbers" this is the first line if len(l) != len(set(l)):
And part b, splits the list into possible shorter lists and checks if they are consecutive.
def example (l, n):
if len(l) != len(set(l)): # part a
return False
for i in range(0, len(l)-n+1): # part b
if l[i:i+3] == sorted(l[i:i+3]):
return True
return False
l = [1, 3, 5, 2, 4, 6]
print example(l, 3)
def solution(A):
counter = [0]*len(A)
limit = len(A)
for element in A:
if not 1 <= element <= limit:
return False
else:
if counter[element-1] != 0:
return False
else:
counter[element-1] = 1
return True
The input to this function is your list.This function returns False if the numbers are repeated.
The below code works even if the list does not start with 1.
def check_is_consecutive(l):
"""
sorts the list and
checks if the elements in the list are consecutive
This function does not handle any exceptions.
returns true if the list contains consecutive numbers, else False
"""
l = list(filter(None,l))
l = sorted(l)
if len(l) > 1:
maximum = l[-1]
minimum = l[0] - 1
if minimum == 0:
if sum(l) == (maximum * (maximum+1) /2):
return True
else:
return False
else:
if sum(l) == (maximum * (maximum+1) /2) - (minimum * (minimum+1) /2) :
return True
else:
return False
else:
return True
1.
l.sort()
2.
for i in range(0,len(l)-1)))
print(all((l[i+1]-l[i]==1)
list must be sorted!
lst = [9,10,11,12,13,14,15,16]
final = True if len( [ True for x in lst[:-1] for y in lst[1:] if x + 1 == y ] ) == len(lst[1:]) else False
i don't know how efficient this is but it should do the trick.
With sorting
In Python 3, I use this simple solution:
def check(lst):
lst = sorted(lst)
if lst:
return lst == list(range(lst[0], lst[-1] + 1))
else:
return True
Note that, after sorting the list, its minimum and maximum come for free as the first (lst[0]) and the last (lst[-1]) elements.
I'm returning True in case the argument is empty, but this decision is arbitrary. Choose whatever fits best your use case.
In this solution, we first sort the argument and then compare it with another list that we know that is consecutive and has no repetitions.
Without sorting
In one of the answers, the OP commented asking if it would be possible to do the same without sorting the list. This is interesting, and this is my solution:
def check(lst):
if lst:
r = range(min(lst), max(lst) + 1) # *r* is our reference
return (
len(lst) == len(r)
and all(map(lst.__contains__, r))
# alternative: all(x in lst for x in r)
# test if every element of the reference *r* is in *lst*
)
else:
return True
In this solution, we build a reference range r that is a consecutive (and thus non-repeating) sequence of ints. With this, our test is simple: first we check that lst has the correct number of elements (not more, which would indicate repetitions, nor less, which indicates gaps) by comparing it with the reference. Then we check that every element in our reference is also in lst (this is what all(map(lst.__contains__, r)) is doing: it iterates over r and tests if all of its elements are in lts).
l = [1, 3, 5, 2, 4, 6]
from itertools import chain
def check_if_consecutive_and_no_duplicates(my_list=None):
return all(
list(
chain.from_iterable(
[
[a + 1 in sorted(my_list) for a in sorted(my_list)[:-1]],
[sorted(my_list)[-2] + 1 in my_list],
[len(my_list) == len(set(my_list))],
]
)
)
)
Add 1 to any number in the list except for the last number(6) and check if the result is in the list. For the last number (6) which is the greatest one, pick the number before it(5) and add 1 and check if the result(6) is in the list.
Here is a really short easy solution without having to use any imports:
range = range(10)
L = [1,3,5,2,4,6]
L = sorted(L, key = lambda L:L)
range[(L[0]):(len(L)+L[0])] == L
>>True
This works for numerical lists of any length and detects duplicates.
Basically, you are creating a range your list could potentially be in, editing that range to match your list's criteria (length, starting value) and making a snapshot comparison. I came up with this for a card game I am coding where I need to detect straights/runs in a hand and it seems to work pretty well.

Does the sum exist in the given list [duplicate]

I am trying to write a function that will not only determine whether the sum of a subset of a set adds to a desired target number, but also to print the subset that is the solution.
Here is my code for finding whether a subset exists:
def subsetsum(array,num):
if num == 0 or num < 1:
return False
elif len(array) == 0:
return False
else:
if array[0] == num:
return True
else:
return subsetsum(array[1:],(num - array[0])) or subsetsum(array[1:],num)
How can I modify this to record the subset itself so that I can print it? Thanks in advance!
Based on your solution:
def subsetsum(array,num):
if num == 0 or num < 1:
return None
elif len(array) == 0:
return None
else:
if array[0] == num:
return [array[0]]
else:
with_v = subsetsum(array[1:],(num - array[0]))
if with_v:
return [array[0]] + with_v
else:
return subsetsum(array[1:],num)
Modification to also detect duplicates and further solutions when a match happened
def subset(array, num):
result = []
def find(arr, num, path=()):
if not arr:
return
if arr[0] == num:
result.append(path + (arr[0],))
else:
find(arr[1:], num - arr[0], path + (arr[0],))
find(arr[1:], num, path)
find(array, num)
return result
You could change your approach to do that more easily, something like:
def subsetsum(array, num):
if sum(array) == num:
return array
if len(array) > 1:
for subset in (array[:-1], array[1:]):
result = subsetsum(subset, num)
if result is not None:
return result
This will return either a valid subset or None.
Thought I'll throw another solution into the mix.
We can map each selection of a subset of the list to a (0-padded) binary number, where a 0 means not taking the member in the corresponsing position in the list, and 1 means taking it.
So masking [1, 2, 3, 4] with 0101 creates the sub-list [2, 4].
So, by generating all 0-padded binary numbers in the range between 0 and 2^LENGTH_OF_LIST, we can iterate all selections. If we use these sub-list selections as masks and sum the selection - we can know the answer.
This is how it's done:
#!/usr/bin/env python
# use a binary number (represented as string) as a mask
def mask(lst, m):
# pad number to create a valid selection mask
# according to definition in the solution laid out
m = m.zfill(len(lst))
return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))
def subset_sum(lst, target):
# there are 2^n binary numbers with length of the original list
for i in xrange(2**len(lst)):
# create the pick corresponsing to current number
pick = mask(lst, bin(i)[2:])
if sum(pick) == target:
return pick
return False
print subset_sum([1,2,3,4,5], 7)
Output:
[3, 4]
To return all possibilities we can use a generator instead (the only changes are in subset_sum, using yield instead of return and removing return False guard):
#!/usr/bin/env python
# use a binary number (represented as string) as a mask
def mask(lst, m):
# pad number to create a valid selection mask
# according to definition in the solution laid out
m = m.zfill(len(lst))
return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))
def subset_sum(lst, target):
# there are 2^n binary numbers with length of the original list
for i in xrange(2**len(lst)):
# create the pick corresponsing to current number
pick = mask(lst, bin(i)[2:])
if sum(pick) == target:
yield pick
# use 'list' to unpack the generator
print list(subset_sum([1,2,3,4,5], 7))
Output:
[[3, 4], [2, 5], [1, 2, 4]]
Note: While not padding the mask with zeros may work as well, as it will simply select members of the original list in a reverse order - I haven't checked it and didn't use it.
I didn't use it since it's less obvious (to me) what's going on with such trenary-like mask (1, 0 or nothing) and I rather have everything well defined.
Slightly updated the below code to return all possible combinations for this problem. Snippet in the thread above will not print all possible combinations when the input is given as subset([4,3,1],4)
def subset(array, num):
result = []
def find(arr, num, path=()):
if not arr:
return
if arr[0] == num:
result.append(path + (arr[0],))
else:
find(arr[1:], num - arr[0], path + (arr[0],))
find(arr[1:], num, path)
find(array, num)
return result
A bit different approach to print all subset through Recursion.
def subsetSumToK(arr,k):
if len(arr)==0:
if k == 0:
return [[]]
else:
return []
output=[]
if arr[0]<=k:
temp2=subsetSumToK(arr[1:],k-arr[0]) #Including the current element
if len(temp2)>0:
for i in range(len(temp2)):
temp2[i].insert(0,arr[0])
output.append(temp2[i])
temp1=subsetSumToK(arr[1:],k) #Excluding the current element
if len(temp1)>0:
for i in range(len(temp1)):
output.append(temp1[i])
return output
arr=[int(i) for i in input().split()]
k=int(input())
sub=subsetSumToK(arr,k)
for i in sub:
for j in range(len(i)):
if j==len(i)-1:
print(i[j])
else:
print(i[j],end=" ")
Rather than using recursion, you could use the iterative approach.
def desiredSum(array, sum):
numberOfItems = len(array)
storage = [[0 for x in range(sum + 1)] for x in range(numberOfItems + 1)]
for i in range(numberOfItems + 1):
for j in range(sum + 1):
value = array[i - 1]
if i is 0: storage[i][j] = 0
if j is 0: storage[i][j] = 1
if value <= j:
noTake = storage[i - 1][j]
take = storage[i - 1][j - value]
storage[i][j] = noTake + take
return storage[numberOfItems][sum]

Divisible by 2: Python [duplicate]

This question already has answers here:
Python Homework - creating a new list
(6 answers)
Closed 9 years ago.
I am trying to write a function called splitList(myList, option) that takes a list and an option which is either 0 or 1 as parameters. If the value of the option is 0 the function returns a list consisting of the elements in myList that are negative and if the value of the option is 1 the function returns a list consisting of the elements in myList that are even (we consider 0 to be an even number, since it is evenly divisible by 2).
For example:
splitList([1,-3,5,7,-9,-11,0,2,-4], 0)
Would return the list:
[-3,-9,-11,-4]
Where as:
splitList([1,-3,5,7,-9,-11,0,2,-4], 1)
Would return the list:
[0,2,-4]
For this problem I must use a for loop.
Here is what I have:
def splitList(myList, option):
negativeValues = []
positiveValues = []
evenValues = []
for i in range(0,len(myList)):
if myList[i] < 0:
negativeValues.append(myList [i])
else:
positiveValues.append(myList [i])
for element in myList:
if option == 1:
myList [i] % 2 == 0
evenValues.append(myList [i])
return evenValues
else:
return negativeValues
The only thing I cannot get it to do is to is sort the list and return all the numbers that are divisible by 2.
Using a loop is a bit redundant here since there's a standard function filter that does what you want: returns a new list with these elements of a list which match a given predicate.
Let's define the predicates first:
def is_even(x):
return x % 2 == 0
def is_negative(x):
return x < 0
Then you can easily define your function in terms of filter:
def splitList(myList, option):
predicate = is_negative if option == 0 else is_even
return filter(predicate, myList)
You can build all your variants from these primitives:
def even_list(numbers):
return [x for x in numbers if not (x & 1)]
def odd_list(numbers):
return [x for x in numbers if x & 1]
def negative_list(numbers):
return [x for x in numbers if x < 0]
def positive_list(numbers):
return [x for x in numbers if x > 0]
Then test:
>>> def test():
... numbers = list(range(-3, 4))
... print even_list(numbers)
... print odd_list(numbers)
... print positive_list(numbers)
... print negative_list(numbers)
...
>>> test()
[-2, 0, 2]
[-3, -1, 1, 3]
[1, 2, 3]
[-3, -2, -1]
Later: so stealing from #Kos, you could write split_list like this:
def split_list(myList, option):
predicate = negative_list if not option else even_list
return predicate(myList)
Or:
def split_list(myList, option):
predicates = [negative_list, even_list]
return predicates[option](myList)
Not sure if it meets your needs if the for-loop is in a list comprehension in a called function.
Also: "Function names should be lowercase, with words separated by underscores as necessary to improve readability."
You return too soon. You first have to complete the foor loop and return after it, not from inside the loop.
Example
for i in range(5):
print i
numbers.append(i)
return numbers //wrong: exit the function on the first pass in the loop.
for i in range(5):
print i
numbers.append(i)
return numbers //right
Besides that why do you calculate the negative valuse list if you don't need it?
def splitList(myList,option):
negative_numbers = [i for i in myList if i < 0]
even_numbers = [i for i in myList if i % 2 == 0]
return sorted(even_numbers) if option else sorted(negative_numbers)
I believe this is what you where trying to achieve:
def splitList(myList,option):
result = []
if option == 0:
for item in myList:
if (item < 0):
result.append(item)
elif option == 1:
for item in myList:
if (item % 2 == 0):
result.append(item)
else:
return "Option Error"
return sorted(result)
print splitList([1,-3,5,7,-9,-11,0,2,-4], 0)
print splitList([1,-3,5,7,-9,-11,0,2,-4], 1)
print splitList([1,-3,5,7,-9,-11,0,2,-4], 2)
Outputs:
[-11, -9, -4, -3]
[-4, 0, 2]
Option Error

Categories