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
Related
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))
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])
I want to find a sequence of n consecutive integers within a sorted list and return that sequence. This is the best I can figure out (for n = 4), and it doesn't allow the user to specify an n.
my_list = [2,3,4,5,7,9]
for i in range(len(my_list)):
if my_list[i+1] == my_list[i]+1 and my_list[i+2] == my_list[i]+2 and my_list[i+3] == my_list[i]+3:
my_sequence = list(range(my_list[i],my_list[i]+4))
my_sequence = [2,3,4,5]
I just realized this code doesn't work and returns an "index out of range" error, so I'll have to mess with the range of the for loop.
Here's a straight-forward solution. It's not as efficient as it might be, but it will be fine unless you have very long lists:
myarray = [2,5,1,7,3,8,1,2,3,4,5,7,4,9,1,2,3,5]
for idx, a in enumerate(myarray):
if myarray[idx:idx+4] == [a,a+1,a+2,a+3]:
print([a, a+1,a+2,a+3])
break
Create a nested master result list, then go through my_sorted_list and add each item to either the last list in the master (if discontinuous) or to a new list in the master (if continuous):
>>> my_sorted_list = [0,2,5,7,8,9]
>>> my_sequences = []
>>> for idx,item in enumerate(my_sorted_list):
... if not idx or item-1 != my_sequences[-1][-1]:
... my_sequences.append([item])
... else:
... my_sequences[-1].append(item)
...
>>> max(my_sequences, key=len)
[7, 8, 9]
A short and concise way is to fill an array with numbers every time you find the next integer is the current integer plus 1 (until you already have N consecutive numbers in array), and for anything else, we can empty the array:
arr = [4,3,1,2,3,4,5,7,5,3,2,4]
N = 4
newarr = []
for i in range(len(arr)-1):
if(arr[i]+1 == arr[i+1]):
newarr += [arr[i]]
if(len(newarr) == N):
break
else:
newarr = []
When the code is run, newarr will be:
[1, 2, 3, 4]
#size = length of sequence
#span = the span of neighbour integers
#the time complexity is O(n)
def extractSeq(lst,size,span=1):
lst_size = len(lst)
if lst_size < size:
return []
for i in range(lst_size - size + 1):
for j in range(size - 1):
if lst[i + j] + span == lst[i + j + 1]:
continue
else:
i += j
break
else:
return lst[i:i+size]
return []
mylist = [2,3,4,5,7,9]
for j in range(len(mylist)):
m=mylist[j]
idx=j
c=j
for i in range(j,len(mylist)):
if mylist[i]<m:
m=mylist[i]
idx=c
c+=1
tmp=mylist[j]
mylist[j]=m
mylist[idx]=tmp
print(mylist)
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]
I currently use this code:
""" Replace all occurrences of subsequence a with b in list l """
def replace_subsequence(l,a,b):
for i in range(len(l)):
if(l[i:i+len(a)] == a):
l[i:i+len(a)] = b
Example:
>>> l = [1,2,3]
>>> replace_subsequence(l,[2,3],[4])
>>> l
[1, 4]
Is there a more efficient and/or elegant way to do this ?
To improve efficiency, you can use the Boyer–Moore string search algorithm when searching for a sublist in a list
Code (credits)
def match(pattern, list):
matches = []
m = len(list)
n = len(pattern)
rightMostIndexes = preprocessForBadCharacterShift(pattern)
alignedAt = 0
while alignedAt + (n - 1) < m:
for indexInPattern in xrange(n-1, -1, -1):
indexInlist = alignedAt + indexInPattern
x = list[indexInlist]
y = pattern[indexInPattern]
if indexInlist >= m:
break
if x != y:
r = rightMostIndexes.get(x)
if x not in rightMostIndexes:
alignedAt = indexInlist + 1
else:
shift = indexInlist - (alignedAt + r)
alignedAt += (shift > 0 and shift or alignedAt + 1)
break
elif indexInPattern == 0:
matches.append(alignedAt)
alignedAt += 1
return matches
def preprocessForBadCharacterShift(pattern):
map = { }
for i in xrange(len(pattern)-1, -1, -1):
c = pattern[i]
if c not in map:
map[c] = i
return map
if __name__ == "__main__":
matches = match("ana", "bananas")
for integer in matches:
print "Match at:", integer
print (matches == [1, 3] and "OK" or "Failed")
matches = match([1, 2, 3], [0, 1, 2,3 , 4, 5, 6])
for integer in matches:
print "list Match at:", integer
print (matches)
It definitely isn't elegant, but I'm wondering if converting to strings and using string.replace would perform better if your data is as simple as in the example...
def strx(l):
return str(l).strip('[]')
def replace_substring(l, a, b):
return strx(l).replace( strx(a), strx(b) ).split(', ')
Using xrange is a simple improvement that will speed up your code. xrange returns a generator, so performance improvements will be particualy noticeable for long lists. But even with your really short test code I get a decent increase.
Using timeit:
replace_subsequence 0.337936162949, 100000 runs
replace_subsequence_xrange 0.275990962982, 100000 runs
Additionally you should assign a variable to len(a) outside of the loop, this way you won't keep calling the len() function. This will also yield a significant speedup.