Recursively rearrange a sequence of integers from even to odd - python
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
Related
Get a list of numbers that adds up to a number "n" (using repetition of number) - how would one consider the case of using same number multiple times?
def getList(n, input_list, caching_list): The function should return a list that adds up to a number "n" using numbers from the input_list, given that numbers can be repeated. Looking to use recursion. current code: def getList(n, input_list, caching_list): if n == 0 : return caching_list if n < 0 or len(input_list) == 0: return [] for i in input_list: if find_sum(n-i,input_list,caching_list) == caching_list: caching_list.append(i) return caching_list return [] example n = 13, input_list= [2,3,5] should result in [2,2,2,2,2,3] or [5,5,2] or anything that adds to 13. Doing this with using a number just 1 time is easy, but how would one consider the case of using same number multiple times?
With recursion, this can be solved using a depth-first search (DFS) algorithm, but it can throw RecursionError: maximum recursion depth exceeded in comparison def find(n2, plist): result = [] def find2(n): if n == 0: return True if n < 0: return False for p in plist: if find2(n-p): result.append(p) return True find2(n2) return result print(find(17, [2,3,5])) # [3, 2, 2, 2, 2, 2, 2, 2] print(find(7, [3,5])) # [] print(find(77777, [3,5,7,11])) # recursion error To get rid of the recursion error, recursive DFS can be rewritten into iterative DFS.
I find itertools can be very handy for stuff like this. I am sure there are better ways to do it, but this might get you want you need: import itertools def find_sum(n, p_list): max_len = n // min(p_list) min_len = n // max(p_list) for i in range(min_len, max_len+1): I = itertools.combinations_with_replacement(p_list, i) for j in I: if(sum(j) == n): return(list(j)) return([]) print(find_sum(17,[2,3,5])) # [2, 5, 5, 5] print(find_sum(7, [3, 5])) # [] You could easily alter the code to give you all combinations. def find_sum(n, p_list): max_len = n // min(p_list) min_len = n // max(p_list) answers = [] for i in range(min_len, max_len+1): I = itertools.combinations_with_replacement(p_list, i) for j in I: if(sum(j) == n): answers.append(list(j)) return(answers) find_sum(17,[2,3,5]) #[[2, 5, 5, 5], [2, 2, 3, 5, 5], [3, 3, 3, 3, 5], [2, 2, 2, 3, 3, 5], [2, 3, 3, 3, 3, 3], [2, 2, 2, 2, 2, 2, 5], [2, 2, 2, 2, 3, 3, 3], [2, 2, 2, 2, 2, 2, 2, 3]] Regarding #dantebarba's comment, I haven't really looked to see how it will scale for large problems and there may be more efficient approaches.
These 3 lines of code should raise some red flags: if find_sum(n-i,p,p_list,sum_list) == sum_list: sum_list.append(i) return sum_list You have a recursive function storing its results in sum_list, modifying it, and also depending on its values for equality checks. This makes your program extremely difficult to reason about. Does the behavior change if you swap the arguments around the equality sign? I have no idea. In general, your recursive programs should try to avoid passing their result as a parameter. Since that if statement is really asking whether we can make a certain sum, why not break that into a separate function? def can_sum(n, p_list, cache={}): if n in cache: return cache[n] if n == 0: return True if n < 0: return False return any(can_sum(n-p, p_list) for p in p_list) You want to use some kind of caching (otherwise, your program is exponential-time), and functools.cache is preferable if you can use outside libraries, but this will do the job. How should your find_sum function return results without passing the result as a parameter? Just add your value to the end, exactly like your code did: def find_sum(n, p_list): for p in p_list: if can_sum(n-p, p_list): return find_sum(n-p, p_list) + [p] return []
Why is my code not following the command?
def pairs(x): for num in x: if num == num : return x y = [2, 2, 2, 2, 2, 4, 3, 3] pairs (y) print (y) this is returning [2, 2, 2, 2, 2, 4, 3, 3] but I want to return [2,2,3] I've tried 3 codes already other than this one help me
Your code seems to be intended to find all the numbers that exist in pairs in the list. The best way would be (for a sorted list) to just cycle through the list and check successive elements. Your code just matches if the current number is the same as the current numbers always returns true and returns all elements. A correct Code might be: y = [2, 2, 2, 2, 2, 4, 3, 3] y=sorted(y) # Sorts the given list def pairs(arr): i = 0 # Counter variable res = [] #result list while i < len(arr)-1: if arr[i] == arr[i+1]: res.append(arr[i]) # If the successive elements are the same, add # it to the result array and since we have already # checked the next element, increment the counter by # two i+=2 else: i+=1 # If the elements are different we need to check the # next element as well so increment by 1 return res print(pairs(y))
You are comparing the element with itself which is always true. Here is the correct logic y = [2, 2, 2, 2, 2, 4, 3, 3] filt = [] i=0 while (i< (len(y)-1)): if y[i] == y[i+1]: filt.append(y[i]) i+=1 i+=1 print(filt)
How to fix separate outputs in a recursive list
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] []
How to give a command for the next iteration
Im trying to write a code to say that if a condition is met of a value in a list then in the next iteration make that value a different one. the problem is i dont know what the code is to tell python to do it in the next iteration my code. list_ = [4, 5, 6, 6, 4, 5] for i in range(0, 10): for j in range(0, len(list_)): if list_[j] == 5: if list_[(j-1) % len(list)] == 4: list_[j][i+1] = 3 but this doesnt work as i get a int' object does not support item assignment error. also i know some of the indentation maybe wrong its because i struggled to put them into here
Your exact expected result is not so clear, but anyway I suggest you this solution that seems solving your problem: list_ = [4, 5, 6, 5, 4, 5] for j in range(0, len(list_)): if (list_[j] == 5) and (list_[j-1] == 4): list_[j] = 3 print(list_) Note: on the first iteration, list_[j-1] refers to the last element of the list.
Perhaps this will suffice, building a new list according to your logic: list_ = [4, 5, 6, 6, 4, 5] lst = [] for i, x in enumerate(list_): if (x == 5) and (list_[i-1] == 4) and (i-1 > 0): lst.append(3) else: lst.append(x) lst # [4, 3, 6, 6, 4, 3] As a list comprehension: [3 if (x == 5) and (list_[i-1] == 4) and (i-1 > 0) else x for i, x in enumerate(list_)] # [4, 3, 6, 6, 4, 3] The (i-1 > 0) prevents searching the end if 5 is in the first position. Three main pythonic themes of this implementation: create a new iterable instead of mutating it enumerate an iterable to reduce the use of indices use booleans to chain conditionals rather than nesting conditionals
Function Definition: Returning a list of even numbers from list of integers
Use the function print_even_values with an input of an integer list and prints each even number on the list. Calling print_even_values([2, 8, 1, 9, 0, 19, 24]) would produce this output in the shell window: 2 8 0 24 My approach is: def print_even_numbers(n:list) -> list: '''Return a list of even numbers given a list of integers''' for x in list: if x % 2 == 0: return(x) assert print_even_numbers([2, 4, 2, 4, 5, 6]) == [2, 4, 2, 4, 6] assert print_even_numbers([4, 1, 3, 2, 5, 9]) == [4, 2] , but there is an error. Also, how do I make my output similar to the question? (i.e. [2, 4, 2, 4, 6] vs.(separate line) 2 4 2 4 6
I think the problem is you are returning a number when it is even, instead of returning the list of even numbers. You should store a number when it is even and then return the list: def print_even_numbers(number_list): even_numbers = [] # define the empty list of even numbers for number in number_list: if number % 2 == 0: # check if number is even even_numbers.append(number) # if it is, store it return even_numbers # Last step returns the list of even numbers
Well also you can use longer version that looks like this: def generate_evens(): result = [] for x in range(1, 50): if x % 2 == 0: result.append(x) return result print(generate_evens()) And you have a short one using this: def generate_evens1(): return [x for x in range(1, 50) if x % 2 == 0] print(generate_evens1())