How to fix separate outputs in a recursive list - python

My function receives a list L and an integer n and returns a list containing the elements of L that are multiples of n, in the same order that they appear in L.
def multiples(L,n):
if len(L) == 0:
return []
if L[0]%n == 0:
print(L[0])
return multiples(L[1:],n)
For example:
multiples([1,2,3,4,5,6,7,8,9,10],2)
should return the list:
[2, 4, 6, 8, 10]
and
multiples([1,2,3,4,5,6,7,8,9,10],5)
should return the list
[5, 10]
and
multiples([3,6,9,12],5)
should return
[]
However, my output are the correct outputs, but separated by a single line and ending in [].

You can do this easier with list comprehension:
a = [i for i in range(11)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
n = 5
result = [x for x in a if x % n == 0] # [5, 10]

If you really want to do it with recursion
def multiples(L,n):
if len(L) == 0:
return []
else:
if L[0]%n == 0:
return [L[0]] + multiples(L[1:],n)
else:
return multiples(L[1:],n)
but as pointed out by others' comments, that may be overkill and a simple inline for loop will do it just fine
[i for i in L if i % n == 0]

All you have to do is to add an extra parameter, call it arr, which will hold all elements that are multiples of n and initialize it to be empty every time you call multiples:
def multiples(L,n,arr):
if len(L) == 0:
return arr
if L[0] % n == 0:
arr.append(L[0])
return multiples(L[1:],n,arr)
print(multiples([1,2,3,4,5,6,7,8,9,10],2,[]))
print(multiples([1,2,3,4,5,6,7,8,9,10],5,[]))
print(multiples([3,6,9,12],5,[]))
This will produce:
[2, 4, 6, 8, 10]
[5, 10]
[]

Related

How to find the location of the nth occurrence of an element in a python list

I need to create a function that takes two arguments: a list lst and a number num. If an element occurs in lst more than num times, remove the extra occurrence(s) and return the result.
So far I have:
def delete_occurrences(lst, num):
for x in lst:
if lst.count(x) > num:
lst.pop(lst.index(x, lst.index(x)+1))
return lst
However for an case such as ([1, 1, 3, 3, 7, 2, 2, 2, 2], 3)
it doesn't delete the correct repetitions.
IIUC, use list.count with a listcomp to slice the extra-occurrences :
L = [1, 1, 3, 3, 7, 2, 2, 2, 2]
def delete_occurrences(lst, num):
return [x for i, x in enumerate(lst) if lst[:i+1].count(x) <= num]
​
Output :
delete_occurrences(L, 3)
#[1, 1, 3, 3, 7, 2, 2, 2]
def delete_occurrences(lst, num):
i = 0
while i < len(lst) :
if lst.count(lst[i]) > num:
lst.pop(i)
i-=1
i+=1
return lst
Here's a solution that keeps your general logic, parsing the list in reverse order so as not to mess up the iteration:
def delete_occurrences(lst, num):
for i in range(len(lst)-1,-1,-1):
if lst.count(lst[i]) > num:
lst.pop(i)
return lst
This works in the way you like:
def delete_occurrences(lst, num):
element_work_done = []
for element in lst:
if lst.count(element) > num and element not in element_work_done:
elm_indices = [i for i, x in enumerate(lst) if x == element]
abundant_occurrences = elm_indices[-(lst.count(element)-num):]
index = 0
for occurrence in abundant_occurrences:
lst.pop(occurrence-index)
index += 1
element_work_done.append(element)
return lst
For bigger lists and data samples, this function out-performs other methods for speed of execution by 10x.

How do I get function to return only numbers in numlist1 that are bigger than all numbers numlist2?

What I have so far:
def get_larger_numbers(numlist1,numlist2):
new_list = []
num = 0
for num in numlist1:
bigger_num = False
for compare in numlist2:
if num > compare:
num1 = num
new_list.append(num1)
return new_list
Expected answer:
r_list = get_larger_numbers([4, 6, 10], [1, 3, 5])
print("Expected: [6, 10]")
Actual answer:
[4,6,10]
Get the max of numlist2 once, then filter numlist1:
numlist1, numlist2 = [4, 6, 10], [1, 3, 5]
M = max(numlist2)
out = [e for e in numlist1 if e>M]
as function
def get_larger_numbers(numlist1,numlist2):
M = max(numlist2)
return [e for e in numlist1 if e>M]
get_larger_numbers([4, 6, 10], [1, 3, 5])
# [6, 10]
fixing your function
even if it is inefficient due to the unnecessary multiple comparisons, here is how to fix your approach:
def get_larger_numbers(numlist1,numlist2):
new_list = []
num = 0
for num in numlist1:
bigger_num = True # consider the number to keep by default
for compare in numlist2:
if num < compare: # if we find a bigger number we won't add
bigger_num = False
break
if bigger_num: # should we add?
new_list.append(num)
return new_list
First get the biggest number in numlist2, then filter the numbers in numlist1 based on whether they are bigger than max_2.
def get_larger_numbers(numlist1,numlist2):
max_2 = max(numlist2)
return [x for x in numlist1 if x >max_2 ]

How do I stop the function when I have a unique list?

I tried a function that would remove both adjacent duplicates in a list. The remove any new duplicate pair and the function will keep going until there are no more duplicate pairs in the list.
I ran into the issue of figuring out how to tell the function to stop once I have a list without adjacent duplicates.
def removepair(no):
i = 1
if len(no) == 0 or len(no) == 1:
return no
while i < len(no):
if no[i] == no[i-1]:
no.pop(i)
no.pop(i-1)
i -= 1
i += 1
return removepair(no)
So far the function will return 0 or single elements after removal:
input: [1, 2, 2, 1] output: []
or
input: [4, 4, 4, 4, 4] output: [4]
But the problem is I don't know how to stop the recursive function once it has a list with more than 1 element:
input: [1,2,3,3,2,1,5,6,7]
expected output: [5,6,7]
We may be able to avoid boolean flags and counters if we set up our recursion carefully:
def removepairs(numbers):
if not numbers: # base case #1, empty
return numbers
first, *second_on = numbers
if not second_on: # base case #2, one element
return numbers
second, *third_on = second_on
if first == second:
return removepairs(third_on)
result = [first] + removepairs(second_on)
if result == numbers:
return numbers # base case #3, no change!
return removepairs(result)
print(removepairs([1, 2, 3, 3, 2, 1, 5, 6, 7]))
OUTPUT
> python3 test.py
[5, 6, 7]
>
If recursive function is not a requirement, it can be simply done using the following code. I have commented the print statement.
def removepair(input_list):
unique_input_list = list(set(input_list))
output_list = list(x for x in unique_input_list if input_list.count(x)%2 == 1)
#print('Input List: ', input_list)
#print('Output list: ', output_list)
return output_list
Input List: [1, 2, 3, 3, 2, 1, 5, 6, 7]
Output list: [5, 6, 7]
Input List: [4, 4, 4, 4, 4]
Output list: [4]
Input List: [1, 2, 3, 3, 2, 1]
Output list: []
Your recursion should stop when no elements where popped from the list, not when the list is almost empty:
def removepair(no):
L = len(no)
if L <= 1:
return no
i = 1
while i < len(no):
if no[i] == no[i-1]:
no.pop(i)
no.pop(i-1)
i -= 1
i += 1
if len(no) < L:
# elements where popped since the list len has decreased
return removepair(no)
else:
return no
Your code is difficult to understand since it uses a mix of recursion and side effects. Usually, you use either one or the other. Here you can replace your recursive call with a while:
def removepair(no):
while True:
L = len(no)
if L <= 1:
return no
i = 1
while i < len(no):
if no[i] == no[i-1]:
no.pop(i)
no.pop(i-1)
i -= 1
i += 1
if len(no) == L: # no elements where popped
return no
But it's not really Pythonic and I think you should not modify the parameter no inside the function but rather return a new list. Why not iterate over the list and do not copy the duplicates in the result?
def removepair(no):
ret = []
for e in no:
if ret and e == ret[-1]: # current element is the same as the last element
ret.pop()
else:
ret.append(e)
return ret
Or with a fold:
def removepair(no):
import functools
return functools.reduce(lambda acc, x: acc[:-1] if acc and acc[-1]==x else acc+[x], no, [])

Rotating values in a list [Python]

I understand this question has been asked before but I haven't seen any that answer it in a way without splitting the list.
say I have a list:
num = [1,2,3,4,5,6]
I want to create a function:
rotate(lst, x):
So that if I call rotate(num, 3) it will globally edit the list num. That way when I later call print(num) it will result in [4,5,6,1,2,3].
I understand that I could write the function something like:
rotate(lst, x):
return [lst[-x:] + lst[:-x]
But I need to do this function without a return statement, and without splitting the list. What I'm thinking would work would be to put the last value of the list into a variable: q = lst[-1] and then from there create a loop that runs x amount of times that continues to move the values towards the end of the list and replacing the 0th position with whatever is stored in q.
One more thing. If I call rotate(lst, -3) then instead of rotating to the "right" it would have to rotate to the "left".
I'm new to python and having trouble wrapping my mind around this concept of manipulating lists. Thank you everyone for your time and effort. I hope this problem was clear enough.
You can use slicing assignment to modify your current strategy to do what you want. You're already generating the rotated list correctly, just modify the list in place with lst[:] = ...
def rotate(lst, x):
lst[:] = lst[-x:] + lst[:-x]
Example in the interactive interpreter:
>>> l = [1, 2, 3, 4, 5, 6]
>>> def rotate(lst, x):
... lst[:] = lst[-x:] + lst[:-x]
...
>>> rotate(l, 2)
>>> l
[5, 6, 1, 2, 3, 4]
Now rotate it backwards:
>>> rotate(l, -2)
>>> l
[1, 2, 3, 4, 5, 6]
>>> rotate(l, -2)
>>> l
[3, 4, 5, 6, 1, 2]
See this answer on a different question: https://stackoverflow.com/a/10623383/3022310
Here is a solution using a double-ended queue.
As required, it modifies the list in place, neither uses return nor uses chunks of the list.
from collections import deque
def rotate(lst, x):
d = deque(lst)
d.rotate(x)
lst[:] = d
num = [1,2,3,4,5,6]
rotate(num,3)
print(num)
rotate(num,-3)
print(num)
produces
[4, 5, 6, 1, 2, 3]
[1, 2, 3, 4, 5, 6]
Please have a look at PMOTW's tutorial on deque
def rotate(lst, num):
copy = list(lst)
for (i, val) in enumerate(lst):
lst[i] = copy[i - num]
Try:
num = [1,2,3,4,5,6]
def rotate(lst,x):
copy = list(lst)
for i in range(len(lst)):
if x<0:
lst[i+x] = copy[i]
else:
lst[i] = copy[i-x]
rotate(num, 2)
print num
Here is a simple method using pop and insert on the list.
num = [1,2,3,4,5,6]
def rotate(lst, x):
if x >= 0:
for i in range(x):
lastNum = lst.pop(-1)
lst.insert(0, lastNum)
else:
for i in range(abs(x)):
firstNum = lst.pop(0)
lst.append(firstNum)
return
print num #[1, 2, 3, 4, 5, 6]
rotate(num, 2)
print num #[5, 6, 1, 2, 3, 4]
rotate(num, -2)
print num #[1, 2, 3, 4, 5, 6]
I believe this satisfies all requirements. The idea is from the Programming Pearls book(http://goo.gl/48yJPw). To rotate a list we can reverse it and then reverse sublists with the rotating index as pivot.
def rotate(num, rot):
if rot < 0:
rot = len(num) + rot
rot = rot - 1
num.reverse()
for i in range(rot/2 + 1):
num[i], num[rot-i] = num[rot-i], num[i]
for i in range(1, (len(num) - rot)/2):
num[rot+ i], num[len(num) - i] = num[len(num) - i], num[rot+ i]
#Testing...
num = range(1, 10)
rot = -1
print num
rotate(num, rot)
print num

Recursively rearrange a sequence of integers from even to odd

This is a practice problem that I've been trying to solve for a while:
Write a recursive Python function that rearranges a sequence of integer values so that all the even values appear before all the odd values.
What I have:
def arrange(x):
even = ''
odd = ''
y = str(x)
if y == '':
return y
elif int(y[0]) % 2 == 0:
even += y[0]
if y[1:] != '':
arrange(int(y[1:]))
else:
odd += y[0]
if y[1:] != '':
arrange(int(y[1:]))
final = int(even + odd)
After running the visualizer, I think the problem in the code lies within the fact that even and odd are reset everytime. Though, I need it all to be in one function. Any advice?
EDIT: Completed in case anyone wanted to use the same practice problem -
even = []
odd = []
def arrange(x):
y = str(x)
if y == '':
return y
elif int(y[0]) % 2 == 0:
even.append(y[0])
if y[1:] != '':
arrange(int(y[1:]))
else:
odd.append(y[0])
if y[1:] != '':
arrange(int(y[1:]))
def complete(x):
evens = ''
odds = ''
arrange(x)
for i in even:
evens += i
for i in odd:
odds += i
return int(evens + odds)
Disclaimer
I do not know any python. I am answering this question as much as a learning exercise for me as the problem is an exercise for you.
I have not checked this answer for syntax errors.
I think your hunch that the problem is due to even and odd being reset on each call is correct - you need to pass them in to rearrange. Here is my attempt:
def arrange(x, evenInput, oddInput):
even = str(evenInput)
odd = str(oddInput)
y = str(x)
if y == '':
return y
elif int(y[0]) % 2 == 0:
even += y[0]
if y[1:] != '':
arrange(int(y[1:]), even, odd)
else:
odd += y[0]
if y[1:] != '':
arrange(int(y[1:]), even, odd)
final = int(even + odd)
I have a different solution, it isn't very efficient if you're working with larger lists*, but I guess for an assignment it's fine:
def evenBeforeOdd(x):
if not x:
return []
if x[0] % 2 == 0: #even
return [x[0]] + evenBeforeOdd(x[1:])
else:
return evenBeforeOdd(x[1:]) + [x[0]]
*: If I remember correctly, adding lists together is pricy (O(n), plus the slicing, which is O(1) in our case, I think), which it needs to do for each item of the list, so the whole thing should be O(n^2). Also it's not very memory efficient, since it must create new lists all the time.
If I actually wanted to solve the problem without the recursivity requirement, it'd simply be something like this:
sorted(myList, key=lambda x: x%2!=0)
Here's a simple solution. For a given index ind recursively apply func for the list, ind ownwards, followed by checking whether the value at ind is even or odd. If odd, just move that value to the end of the list.
When the recursion starts to unwrap, it will begin rearrangement from the end of list and as the stack unwinds, the pervious elements of the list would start to fall in the right places.
def func(lst, ind=0):
if ind < len(lst):
func(lst, ind+1)
if lst[ind] % 2 != 0:
lst.append(lst.pop(ind))
return lst
print func([3,4,6,2,1])
I wasn't sure what your desired output was, or if you wanted it to recurse and keep the structure/order. Here's a swiss army knife.
from pprint import pprint
def even_before_odd(values, keep_structure=False, sort=False):
evens, odds = even_odd(values, keep_structure, sort)
return evens + odds
def even_odd(values, keep_structure=False, sort=False):
evens = []
odds = []
for value in values:
if isinstance(value, list):
_evens, _odds = even_odd(value, keep_structure, sort)
if keep_structure:
# This will insert a sub array
evens.append(_evens)
odds.append(_odds)
else:
# This will append them to the list
evens += _evens
odds += _odds
continue
if value % 2 == 0:
evens.append(value)
else:
odds.append(value)
if sort:
evens = sorted(evens)
odds = sorted(odds)
return evens, odds
values = []
for x in range(0,10):
values.append(list(range(0,10)))
result = even_before_odd(values, False, True)
print "result 1:", ",".join(map(str, result))
result = even_before_odd(values, False, False)
print "result 2:", ",".join(map(str, result))
print "result 3:"
result = even_before_odd(values, True, True)
pprint(result)
Output:
result 1: 0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,6,6,6,6,8,8,8,8,8,8,8,8,8,8,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,5,5,5,5,5,5,5,5,5,5,7,7,7,7,7,7,7,7,7,7,9,9,9,9,9,9,9,9,9,9
result 2: 0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,0,2,4,6,8,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9,1,3,5,7,9
result 3
[[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[0, 2, 4, 6, 8],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9],
[1, 3, 5, 7, 9]]
Here is an efficient, short way to do this (not recursive however).
A string in Python is an iterable, so there actually is no need to keep taking substrings of the original input. Instead, you could filter out the odd and even digits and later concatenate them.
def splitEvenOdd(x):
even = [e for e in x if int(e)%2 == 0]
odd = [o for o in x if int(o)%2 == 0]
even = "".join(even)
odd = "".join(odd)
return even + odd

Categories

Resources