How to create a recursive separator? - python

I am trying to learn recursion and am separating odd and even values in two lists and merging them to another list as below:
Code:
def separateNumbers(L):
evenList = []
oddList = []
main = []
if len(L)==0:
return L
if L[0] % 2 == 0:
evenList.append(L[0])
separateNumbers(L[1:])
if L[0] % 2 == 1:
oddList.append(L[0])
separateNumbers(L[1:])
main.append(evenList)
main.append(oddList)
return main
inputList = [1,2,3,4,5,6,7,8,9,10]
L = separateNumbers(inputList)
print(L)
Input:
L = [1,2,3,4,5,6]
Output:
[[1,3,5], [2,4,6]]
The even and odd arrays reset everytime the recursive function is called, how can I fix this?
Tried with inner function:
def separateNumbers(L):
evenList = []
oddList = []
main = []
def inner(L):
if len(L)==0:
return L
if L[0] % 2 == 0:
evenList.append(L[0])
inner(L[1:])
if L[0] % 2 == 1:
oddList.append(L[0])
inner(L[1:])
main.append(evenList)
main.append(oddList)
return main
a = inner(L)
return a
Output:
[[2, 4, 6, 8, 10], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10], [1, 3, 5, 7, 9], [2, 4, 6, 8,
10], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10], [1, 3, 5, 7, 9], [2, 4, 6, 8, 10], [1, 3, 5, 7, 9]]

You don't need a nested function. try:
def separate_numbers(lst):
if not lst: # empty list
return [], []
odd, even = separate_numbers(lst[1:]) # recursion call
if lst[0] % 2: # if the first item is odd
return [lst[0], *odd], even
else: # if even
return odd, [lst[0], *even]
lst = [1,2,3,4,5,6,7,8,9,10]
print(separate_numbers(lst)) # ([1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
The function calls itself using the tail part of the input list, receiving two lists: odd for odd numbers and even for even numbers. Then it returns those lists, after attaching the head element lst[0] to one of the lists.

Related

How can I make this python function generate such a list [[1], [1, 2]...[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]?

all = []
def generate(i, current):
if i < 11:
current.append(i)
all.append(current)
i+= 1
generate(i, current)
generate(1, [])
print(all)
I want this function to generate
[[1], [1, 2]...[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
instead of
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]],
but don't know how to fix it.
Do you know the solution?
Here's my go:
def listGen(start, stop):
res = []
for i in range(start, stop+1):
res.append([x for x in range(start, i+1)])
return res
You could also simplify this to:
def listGen(start, stop):
return [[x for x in range(start, i+1)] for i in range(start, stop+1)]
Input: print(listGen(1, 10))
Output: [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
def generate_array():
result = []
for i in range(1, 11):
current_array = []
for j in range(1, i + 1):
current_array.append(j)
result.append(current_array)
return result
print(generate_array())
The code uses two nested for loops, where the outer loop iterates over range(1, 11) and the inner loop iterates over range(1, i + 1). The values of i and j are used to generate the sublists and append them to the result list, which is returned at the end of the function.
The core issue you have is that when you do:
all.append(current)
current is the exact same list all over the place so when you append to it in the prior line you effectively append to it everywhere. To fix that and the lightest change to your code you would append to copy of it.:
all = []
def generate(i, current):
if i < 11:
current.append(i)
all.append(current.copy()) ## <--- append a copy
i+= 1
generate(i, current)
generate(1, [])
print(all)
alternatively you could pass a copy like:
all = []
def generate(i, current):
if i < 11:
current.append(i)
all.append(current)
i+= 1
generate(i, current.copy()) ## <--- pass a copy
generate(1, [])
print(all)
In either case, the important part is that we get a distinct current to work with.
Note that the use of all as a variable clobbers the function all() and you might not want to do that. As I'm sure lots of others will point out, there are many ways to skin this cat.

Mutually Exclusive Lists Python

I'm trying to simplify this code so it doesn't use two for loops. The aim is to end up with a list of numbers that exist in one list but not the other ie. mutually exclusive.
Here is the code:
list1 = [1, 1, 2, 4, 6, 6, 9]
list2 = [1, 2, 3, 5, 6, 7, 8]
def mutually_exclusive(list1,list2):
new_list = []
for x in list1:
if x not in list2:
new_list.append(x)
else:
pass
for y in list2:
if y not in list1:
new_list.append(y)
else:
pass
return new_list
mutually_exclusive(list1,list2)
and the desired result:
[4, 9, 3, 5, 7, 8]
any help much appreciated thanks.
I have tried zip but doesn't yield all results.
You could also do it like this:
list1 = [1, 1, 2, 4, 6, 6, 9]
list2 = [1, 2, 3, 5, 6, 7, 8]
def mutually_exclusive(list1,list2):
return list(set(list1)^set(list2))
print(mutually_exclusive(list1, list2))
Result:
[3, 4, 5, 7, 8, 9]
You can do the following using symmetric_difference:
l1 = [1, 1, 2, 4, 6, 6, 9]
l2 = [1, 2, 3, 5, 6, 7, 8]
list(set(l1).symmetric_difference(set(l2)))
In [7]: l1
Out[7]: [1, 1, 2, 4, 6, 6, 9]
In [8]: l2
Out[8]: [1, 2, 3, 5, 6, 7, 8]
In [9]: list(set(l1).symmetric_difference(set(l2)))
Out[9]: [3, 4, 5, 7, 8, 9]

Trying to increase item in a python list to get all options

I'm trying to take a list of numbers and increase them by a certain amount(1 in my example) up to a certain range(5 in my example) but for some reason it's not doing it the way I was expecting:
Given this list:
[1, 5, 7, 9, 3]
I expect:
[1, 5, 7, 9, 3]
[2, 5, 7, 9, 3]
[3, 5, 7, 9, 3]
[4, 5, 7, 9, 3]
[5, 5, 7, 9, 3]
[1, 6, 7, 9, 3]
[2, 7, 7, 9, 3]
[3, 8, 7, 9, 3]
[4, 9, 7, 9, 3]
[5, 10, 7, 9, 3]
... and so on
Here's my code:
# create list
list_of_nums = [1, 5, 7, 9, 3]
# variable of increase
increase_range = 5
range_per_increase = 1
for idx, i in enumerate(list_of_nums):
current_item = i
while current_item < i+increase_range:
copy_of_list = list_of_nums
current_item = current_item+range_per_increase
copy_of_list[idx] = current_item
print(copy_of_list)
break
Output:
[4, 7, 9, 11, 5]
[4, 8, 9, 11, 5]
[4, 8, 10, 11, 5]
[4, 8, 10, 12, 5]
[4, 8, 10, 12, 6]
What am I doing wrong or is there a easier way to get the output I want?
Update: I think my above example I get incrementals for each item then move on, but is it possible to get all combinations so the first item and the others item are incremented. I want all combinations for the lists within each numeric range while preserving the order.
There is an easier way to get this. The built in itertools.product method can do most of the work.
from itertools import product
list_of_nums = [1, 5, 7, 9, 3]
increase_range = 5
range_per_increase = 1
choices_list = []
for num in list_of_nums:
choices_list.append([])
currentAdder = num
while currentAdder < num + increase_range:
choices_list[-1].append(currentAdder)
currentAdder += range_per_increase
print(choices_list)
# Prints [[1, 2, 3, 4, 5], [5, 6, 7, 8, 9], ...] with all the options for each item.
print("\n\n\n")
for nums in product(*choices_list): # Unpack choices_list into product
print(list(nums)) # Since each output should be a list, convert from tuple to list

Splitting list of elements without numpy array function [duplicate]

This question already has answers here:
How do I split a list into equally-sized chunks?
(66 answers)
Closed 1 year ago.
Example: I have a list:
[8, 3, 4, 1, 5, 9, 6, 7, 2]
And I need to make it look like this but without using numpy.array_split():
[[8, 3, 4], [1, 5, 9], [6, 7, 2]]
How can I do it? Not only for this one case, but when I have 4 elements, I want to have 2 and 2, (9 - 3,3,3 and 16 - 4,4,4,4) etc.
You can get the square root of the list's length then split it using a list comprehension. This will work for lists with the length of 4, 9, 16, ...:
lst = [8, 3, 4, 1, 5, 9, 6, 7, 2]
lst2 = [8, 3, 4, 1]
def split_equal(lst):
len_ = len(lst)
# returns emtpy list, if the list has no item.
if len_ == 0:
return []
n = int(len_ ** 0.5)
return [lst[i:i + n] for i in range(0, len_, n)]
output:
[[8, 3, 4], [1, 5, 9], [6, 7, 2]]
[[8, 3], [4, 1]]
You can use that:
def splitter(inlist):
n = len(inlist)
m = int(n ** 0.5)
if m*m != n:
raise Exception("")
return [[inlist[i+j] for j in range(m)] for i in range(m)]
print(splitter([8, 3, 4, 1]))
print(splitter([8, 3, 4, 1, 5, 9, 6, 7, 2]))
print(splitter([8, 3, 4, 1, 5, 9, 6, 7, 2, 8, 3, 4, 1, 5, 9, 6]))
Result:
[[8, 3], [3, 4]]
[[8, 3, 4], [3, 4, 1], [4, 1, 5]]
[[8, 3, 4, 1], [3, 4, 1, 5], [4, 1, 5, 9], [1, 5, 9, 6]]
Carefull, it will crash if the square of the len of input list is not integer.
def equal_array_split(arr, split_arr_len):
array_length = len(arr)
if array_length % split_arr_len == 0:
return [arr[i:i+split_arr_len] for i in range(0,array_length,split_arr_len)]
else:
return "Invalid split array length!!"
print(equal_array_split([1,2,3,4,5,6,7,8,9],3))
print(equal_array_split([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],4))
print(equal_array_split([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],8))
print(equal_array_split([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],2))
Output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
[[1, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11, 12, 13, 14, 15, 16]]
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]]
You can slice the list with a list comprehension. Assuming the input is a square number length:
import numpy as np
arr = [8, 3, 4, 1, 5, 9, 6, 7, 2]
n = int(np.sqrt(len(arr)))
result = [arr[i*n:(i+1)*n] for i in range(int(n))]
the split value being a square
list = [8, 3, 4, 1, 5, 9, 6, 7, 2]
result = []
N = split_value #split_value being the value required to split the list
for i in range(0,len(list),N):
result.append(list[i:i+N])
print(result)
Whitout numpy....
a = [8, 3, 4, 1, 5, 9, 6, 7, 2]
splitedSize = 3
a_splited = [a[x:x+splitedSize] for x in range(0, len(a), splitedSize)]
print(a_splited)

python generate sublist with offset and condition

Hey I'm trying to generate sublists of a list. For example I've a list like this:
l = [1,2,3,4,5,6,7,8,9,10,11,12]
I want to split them in sublists with the length of 4. But to first element is the same like the last element from the previous list AND like I said it must have the length of 4. Like this:
l1 = [1,2,3,4]
l2 = [4,5,6,7]
l3 = [7,8,9,10]
l4 = [10, 11, 12] <-- should be ignored
Does someone has an idea?! I'm thinking about an generator but I'm not quite sure.
A simple but flexible generator implementation:
def overlapping_sublists(l, n, overlap=1, start=0):
while start <= len(l) - n:
yield l[start:start+n]
start += n - overlap
Example usage:
>>> l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
>>> list(overlapping_sublists(l, 4))
[[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10]]
>>> list(overlapping_sublists(l, 4, 2, 3))
[[4, 5, 6, 7], [6, 7, 8, 9], [8, 9, 10, 11]]
a = []
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
for i in range(0, len(l)-3, 3):
a.append(l[i:i+4])
will give a = [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10]]
or you can use as a list comprehension:
[l[i:i+4] for i in range(0, len(l)-3, 3)]
print([l[i:i+4] for i in range(0, len(l), 3)])
Output:
[[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10], [10, 11, 12]]
Only sublists of length 4:
print([m for m in [l[i:i+4] for i in range(0, len(l), 3)] if len(m) == 4])
Output:
[[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10]]
Using generators:
for n in (m for m in (l[i:i+4] for i in range(0, len(l), 3)) if len(m) == 4):
print(n)
Output:
[1, 2, 3, 4]
[4, 5, 6, 7]
[7, 8, 9, 10]

Categories