How to weave two lists using recursion in Python - python

I want to weave two lists and output all the possible results.
For example,
input: two lists l1 = [1, 2], l2 = [3, 4]
output: [1, 2, 3, 4], [1, 3, 2, 4], [1, 3, 4, 2], [3, 1, 2, 4], [3, 1, 4, 2], [3, 4, 1, 2]
Note: I need to keep the order in each list (e.g. 1 is always before 2, and 3 is always before 4)
The way I am solving this is by removing the head from one list, recursing, and then doing the same thing with the other list. The code is below:
all_possibles = []
def weaveLists(first, second, added):
if len(first) == 0 or len(second) == 0:
res = added[:]
res += first[:]
res += second[:]
all_possibles.append(res)
return
cur1 = first[0]
added.append(cur1)
first = first[1:]
weaveLists(first, second, added)
added = added[:-1]
first = [cur1] + first
cur2 = second[0]
added.append(cur2)
second = second[1:]
weaveLists(first, second, added)
added = added[:-1]
second = [cur2] + second
weaveLists([1, 2], [3, 4], [])
print(all_possibles)
The result I got is:
[[1, 2, 3, 4], [1, 3, 2, 4], [1, 3, 4, 2], [1, 3, 1, 2, 4], [1, 3, 1, 4, 2], [1, 3, 1, 4, 1, 2]]
I couldn't figure out why for the last three lists, the heading 1 from the first list is not removed.
Can anyone help? Thanks!

The reason you get those unexpected results is that you mutate added at this place:
added.append(cur1)
...this will affect the caller's added list (unintentionally). While the "undo" operation is not mutating the list:
added = added[:-1]
This creates a new list, and therefore this "undo" action does not roll back the change in the list of the caller.
The easy fix is to replace the call to append with:
added = added + [cur1]
And the same should happen in the second block.
It is easier if you pass the new values for the recursive call on-the-fly, and replace those two code blocks with just:
weaveLists(first[1:], second, added + [first[0]])
weaveLists(first, second[1:], added + [second[0]])

Here is another way to do it: we generate the possible indices of the items of the first list inside the weaved list, and fill the list accordingly.
We can generate the indices with itertools.combinations: it's the combinations of the indices of the weaved list, taking len(first_list) of them each time.
from itertools import combinations
​
def weave(l1, l2):
total_length = len(l1) + len(l2)
# indices at which to put items from l1 in the weaved output
for indices in combinations(range(total_length), r=len(l1)):
out = []
it1 = iter(l1)
it2 = iter(l2)
for i in range(total_length):
if i in indices:
out.append(next(it1))
else:
out.append(next(it2))
yield out
Sample run:
l1 = [1, 2]
l2 = [3, 4]
​
for w in weave(l1, l2):
print(w)
​
[1, 2, 3, 4]
[1, 3, 2, 4]
[1, 3, 4, 2]
[3, 1, 2, 4]
[3, 1, 4, 2]
[3, 4, 1, 2]
Another sample run with a longer list:
l1 = [1, 2]
l2 = [3, 4, 5]
​
for w in weave(l1, l2):
print(w)
​
[1, 2, 3, 4, 5]
[1, 3, 2, 4, 5]
[1, 3, 4, 2, 5]
[1, 3, 4, 5, 2]
[3, 1, 2, 4, 5]
[3, 1, 4, 2, 5]
[3, 1, 4, 5, 2]
[3, 4, 1, 2, 5]
[3, 4, 1, 5, 2]
[3, 4, 5, 1, 2]

Related

Permutation with recursion not printing all values in python?

I am writing python code to print all permutation of a number.
Below is my code:
a=[1,2,3,4]
for i in range(len(a)):
temp=a[:]
temp[0],temp[i]=temp[i],temp[0]
def p(temp,i):
k=i+1
if k ==len(a)-1:
print(temp)
return
temp[k],temp[k+1]=temp[k+1],temp[k]
p(temp,k)
temp[k],temp[k+1]=temp[k+1],temp[k]
p(temp,k)
p(temp,i=0)
The idea is to replace every integer at first place and permutate remaining.
That's what this for loop is doing:
for i in range(len(a)):
temp=a[:]
temp[0],temp[i]=temp[i],temp[0]
But,for every permutation starting with i,it only prints 4 permutations.
for ex:
Starting with 1,the permutations should be:
[1,2,3,4]
[1,2,4,3]
[1,3,2,4]
[1,3,4,2]
[1,4,3,2]
[1,4,2,3]
But,its only printing
[1,2,3,4]
[1,2,4,3]
[1,3,2,4]
[1,3,4,2]
4 at second place is not getting printed.
Missing:
[1,4,3,2]
[1,4,2,3]
Can anyone tell me what am I doing wrong?
Edited code:
def p(temp, k=0):
if k == len(temp):
print(temp)
return
for i in range(k, len(temp)):
temp[k], temp[i] = temp[i], temp[k]
p(temp, k+1)
temp[k], temp[i] = temp[i], temp[k]
p([1,2,3,4])
result:
[1, 2, 3, 4]
[1, 2, 4, 3]
[1, 3, 2, 4]
[1, 3, 4, 2]
[1, 4, 3, 2]
[1, 4, 2, 3]
[2, 1, 3, 4]
[2, 1, 4, 3]
[2, 3, 1, 4]
[2, 3, 4, 1]
[2, 4, 3, 1]
[2, 4, 1, 3]
[3, 2, 1, 4]
[3, 2, 4, 1]
[3, 1, 2, 4]
[3, 1, 4, 2]
[3, 4, 1, 2]
[3, 4, 2, 1]
[4, 2, 3, 1]
[4, 2, 1, 3]
[4, 3, 2, 1]
[4, 3, 1, 2]
[4, 1, 3, 2]
[4, 1, 2, 3]
Heres a correction for your process
a=[1,2,3,4]
def p(temp,i):
k=i+1
if k ==len(a)-1:
print(temp)
return
temp[k],temp[k+1]=temp[k+1],temp[k]
prev = temp.copy()
p(temp,k)
temp[k],temp[k+1]=temp[k+1],temp[k]
p(temp,k)
temp[k],temp[k+1]=temp[k+1],temp[k]
if temp != prev:
p(temp,k)
for i in range(len(a)):
temp=a[:]
temp[0],temp[i]=temp[i],temp[0]
p(temp,i=0)
The problem was that you were only rearranging the temp list 2 times in the actual call of the function p from the for loop. Calling it three times made it to contain '4' in the second place of the permutation. The if statement I added is to check if the previous rearranged temp is not the as the current rearrange temp, this removed duplicate results which occurred when calling the function p three times. Although I do recommend Hamid's answer.
The logic seems to be wrong. You are swapping the neighboring elements. Because of that, you are unable to generate all the permutations. Ideally, you want to recursively repeat the logic of fixing the first element.

Split one list of numbers into several based on a simple condition, lead and lag in lists [duplicate]

This question already has answers here:
Split List By Value and Keep Separators
(8 answers)
Closed 1 year ago.
Is there an easy way to split the list l below into 3 list. I want to cut the list when the sequence starts over. So every list should start with 1.
l= [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]
l1 = [1, 2, 3,4, 5]
l2=[1,2,3,4]
l3=[1,2,3,4]
My original thought was to look at the lead value and implement a condition inside a for loop that would cut the list when x.lead < x. But how do I use lead and lag when using lists in python?
NumPy solution
import numpy as np
l = [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]
parts = [list(i) for i in np.split(l,np.flatnonzero(np.diff(l)-1)+1)]
print(parts)
output
[[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 4]]
Explanation: I first find differences between adjacent elements using numpy.diff, then subtract 1 to be able to use numpy.flatnonzero to find where difference is other than 1, add 1 (note that numpy.diff output length is input length minus 1) to get indices for use in numpy.split, eventually convert it to list, as otherwise you would end with numpy.arrays
What about this:
l = [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]
one_indices = [i for i, e in enumerate(l) if e == 1]
slices = []
for count, item in enumerate(one_indices):
if count == len(one_indices) - 1:
slices.append((item, None))
else:
slices.append((item, one_indices[count + 1]))
sequences = [l[x[0] : x[1]] for x in slices]
print(sequences)
Out:
[[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 4]]
Another way without numpy,
l= [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]
start = 0
newlist = []
for i,v in enumerate(l):
if i!=0 and v==1:
newlist.append(l[start:i])
start = i
newlist.append(l[start:i+1])
print(newlist)
Working Demo: https://rextester.com/RYCV85570

How to create a duplicate list in python

I want to create a date list that- contains the list of dates of one week but each date should be there 4 times in that list. like this:
[1-jan-2018, 1-jan-2018, 1-jan-2018, 1-jan-2018, 2-jan-2018, 2-jan-2018, 2-jan-2018, 2-jan-2018, 3-jan-2018, 3-jan-2018, 3-jan-2018, 3-jan-2018, 4-jan-2018, 4-jan-2018, 4-jan-2018, 4-jan-2018, 5-jan-2018, 5-jan-2018, 5-jan-2018, 5-jan-2018, 6-jan-2018, 6-jan-2018, 6-jan-2018, 6-jan-2018,7-jan-2018, 7-jan-2018, 7-jan-2018, 7-jan-2018]
I don't exactly have the idea how to do it but here is my attempt:
import pandas as pd
timeSeries = list(pd.date_range(start='1/1/2020', end='7/1/2020'))
print(timeSeries)
This will just create the list of dates of one week but I want the answer in the above format. Can someone please help?
How to duplicate items in a list
A solution is create various list with each element of your primary list repeated N time. In this example, I will duplicated each element four times, so:
old_list = [1,2,3,4]
# [i,i,i,i] will clone each item four times.
new_list = list([i,i,i,i] for i in old_list)
# new_list = [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]]
But, now you will have a list of lists, so you need to transform that result into a list of elements, this operation is called flat. In order to do this in python, you can use the itertools.chain.
import itertools
old_list = [1,2,3,4]
# [i,i,i,i] will clone each item four times.
new_list = list([i,i,i,i] for i in old_list)
# new_list = [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]]
new_list_flatten = list(itertools.chain(*new_list))
# new_list_flatten = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]
You can avoid the usage of * operation by calling itertools.chain.from_iterable:
import itertools
old_list = [1,2,3,4]
# [i,i,i,i] will clone each item four times.
new_list = list([i,i,i,i] for i in old_list)
# new_list = [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]]
new_list_flatten = list(itertools.chain.from_iterable(new_list))
# new_list_flatten = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]
Therefore, this is a code that do what you want:
import itertools
import pandas as pd
time_series = list(pd.date_range(start='1/1/2020', end='7/1/2020'))
newseries = list( itertools.chain.from_iterable((i,i,i,i) for i in time_series) )
print(newseries)

find occurrences of elements of a list in a list of list

i have a list [1, 2, 3]
i want to find number of times the elements of this list appears in a list of list:
lol = [[1, 2, 4, 5], [2, 3, 1, 2], [1, 2, 3], [3, 2, 6, 7, 1], [1, 4, 2, 6, 3]]
occurrences = 4
What I’m doing currently is the following:
a = [1, 2, 3]
lol = [[1, 2, 4, 5], [2, 3, 1, 2], [1, 2, 3], [3, 2, 6, 7, 1], [1, 4, 2, 6, 3]]
def get_count(a, b):
a = set(a)
return sum([a.issubset(x) for x in b])
print(get_count(a, lol))
This method works but is quite slow when I have 100s of 1000s of list to compare with a list of list (lol remains static!)
can we also preserve the "order" of the elements? there can be other elements in between. in this case occurrences will be 2 for the above case
Why not try:
testlist = lol ##Create a test list that we will work with
for i in range len(testlist): ##Start a loop that will repeat length of testlist times
if a in testlist: ##If/When it finds the first occurrence of the list a
Occurrences =+ 1 ##It adds 1 to the amount off occurences
Pos = testlist.index(a)
testlist.del(Pos) ##It deletes the instance from the list.
This should work

Why does recursion overwrite values in a list that is passed along?

This recusion is adapted from http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/ and does indeed print out all possible unique combination of arr with length r.
What I want from it is to save all possible combination in a list to further use this algorithm in another program. Why is the values overritten in combArray in the recustion and how do I solve this?
def combRecursive(arr, data, start, end, index, r, combArray):
if index == r:
combArray.append(data)
return combArray
i = start
while True:
if i > end or end - i + 1 < r - index:
break
data[index] = arr[i]
combArray = combRecursive(arr, data, i + 1, end, index + 1, r, combArray)
i += 1
return combArray
def main():
arr = [1, 2, 3, 4, 5]
r = 3
n = len(arr)
data = [9999999, 9999999, 9999999]
combArray = []
combArray = combRecursive(arr, data, 0, n-1, 0, r, combArray)
print("All possible unique combination is: ")
for element in combArray:
print(element)
Result as of now:
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
What I want:
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 3, 4]
[1, 3, 5]
[1, 4, 5]
[2, 3, 4]
[2, 3, 5]
[2, 4, 5]
[3, 4, 5]
You initialize data, and from then on make changes to it & add it to combArray, which means you are always adding the same array to combArray, so all of its elements are the same. If you want the elements to be distinct arrays, you need to make a new array for each you want to add to combArrays (by, for example, making a copy of data).

Categories

Resources