getting empty list even though appending while using recursion - python

I am trying to print all subsequences of the list "l" in the code but here i want the answer to be stored in "proc" list.But when executing the below code i am getting empty lists of list.I am practising recursion problems.I stuck to understand why i am getting empty lists of list which is "proc" list
proc = [] #global array
def fun(t,lst,i,n):
if(i==n):
print(t)
proc.append(t) #appending to the global array
return
t.append(lst[i])
fun(t,lst,i+1,n)
t.pop()
fun(t,lst,i+1,n)
arr = [6,4,2]
n = len(arr)
l = []
for i in range(n):
for j in range(i+1,n):
l.append([i+1,j+1])
fun([],l,0,len(l))
print(proc) #printing the global list proc after executing function```
I want to know why i am getting output as empty lists even though i am appending "t" list to the "proc" list
[[1, 2], [1, 3], [2, 3]]
[[1, 2], [1, 3]]
[[1, 2], [2, 3]]
[[1, 2]]
[[1, 3], [2, 3]]
[[1, 3]]
[[2, 3]]
[]
[[], [], [], [], [], [], [], []]
i want answer to be appended list of t

You have fallen prey to one of the classic Python errors. You are passing [] into the function as t. You then modify t, and pass t into the recursive call. That means there is ONLY ONE LIST t. When you do proc.append(t), you are not grabbing a snapshot of the array. You are appending multiple references to that one list. By the time the function ends, t is empty, so your proc has multiple references to an empty list.
The short term fix is to change to
proc.append( t.copy() )
or
proc.append( t[:] )

Related

Find duplicates within and outside nested list in python

I have a list s:
s=[[1,2,1],[2,2,1],[1,2,1]]
Case 1: Remove the duplicate groups in the list
Case 2: Remove the duplicate values within the groups
Desired Result:
Case 1 : [[1,2,1],[2,2,1]]
Case 2 : [[1,2],[2,1],[1,2]]
I tried using the list(set(s)) but it throws up an error:
unhashable type: 'list'
IIUC,
Case 1:
Convert the lists to tuple for hashing, then apply a set on the list of tuples to remove the duplicates. Finally, convert back to lists.
out1 = list(map(list, set(map(tuple, s))))
# [[1, 2, 1], [2, 2, 1]]
Case 2:
For each sublist, remove the duplicates while keeping order with conversion to dictionary keys (that are unique), then back to list:
out2 = [list(dict.fromkeys(l)) for l in s]
# [[1, 2], [2, 1], [1, 2]]
You need to know that it's not possible in Python to have a set of lists. The reason is that lists are not hashable. The simplest way to do your task in the first case is to use a new list of lists without duplicates such as below:
temp_list = []
for each_element in [[1,2,1],[2,2,1],[1,2,1]]:
if each_element not in temp_list:
temp_set.append(each_element)
print(temp_list)
The output:
[[1, 2, 1], [2, 2, 1]]
The case2 is more simple:
temp_list = []
for each_element in [[1,2,1],[2,2,1],[1,2,1]]:
temp_list.append(list(set(each_element)))
print(temp_list)
And this is the output:
[[1, 2], [1, 2], [1, 2]]
However these codes are not the pythonic way of doing things, they are very simple to be understood by beginners.

Sticky index reference while inserting into 2D list in Python

While attempting to implement a function that produces all permutations given a list of integers, I'm seeing this behavior where the inserts are not occurring as expected.
My code:
def permute(nums):
perms = [[]]
for i in range(len(nums)):
new_perms = perms * (i + 1)
for j in range(len(new_perms)):
new_perms[j].insert(j % len(perms), nums[i])
perms = new_perms
return perms
When calling permute([1, 2, 3]) I'm expecting the perms to grow like:
[[]]
[[1]]
[[2, 1], [1, 2]
[[3, 2, 1], [1, 3, 2], [2, 1, 3], [3, 1, 2], [2, 3, 1], [1, 2, 3]
However, by the second iteration of the interior loop with new_perms: [[1], [1]] I'm expecting it to grow to [[2, 1], [1, 2]], instead I'm getting [[2,1],[2,1]] and then [[2,2,1],[2,2,1]]. On each iteration of the j loop, the number is getting inserted into the current j position of all values of the list simultaneously on each iteration. Not what I was trying to do or expecting.
Ultimately, the code outputs:
[[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1]]
Either this is some subtle reference behavior (yay, learn something new!) or I'm just having a really dumb day ;) Any help appreciated.
PLEASE NOTE: I'm NOT asking for help with an alternate or optimal permutations function! I'm trying to figure out why this particular code is behaving in an unexpected way. Thank you.
Ok, learned a good one here. DEEPCOPY!
import copy
def permute(nums):
perms = [[]]
for i in range(len(nums)):
len_perms = len(perms)
old_perms = perms
perms = []
for _ in range(i+1):
perms += copy.deepcopy(old_perms)
for j in range(len(perms)):
perms[j].insert(j // len_perms, nums[i])
return perms

Remove list from list of lists if condition is met

I have a list of lists containing an index and two coordinates, [i,x,y] eg:
L=[[1,0,0][2,0,1][3,1,2]]
I want to check if L[i][1] is repeated (as is the case in the example for i=0 and i=1) and keep in the list only the list with the smallest i. In the example [2,0,1] would be removed and L would be:
L=[[1,0,0][3,1,2]]
Is there a simple way to do such a thing?
Keep a set of the x coordinates we've already seen, traverse the input list sorted by ascending i and build and output list adding only the sublists whose x we haven't seen yet:
L = [[1, 0, 0], [2, 0, 1], [3, 1, 2]]
ans = []
seen = set()
for sl in sorted(L):
if sl[1] not in seen:
ans.append(sl)
seen.add(sl[1])
L = ans
It works as required:
L
=> [[1, 0, 0], [3, 1, 2]]
There are probably better solution but you can do with:
i1_list=[]
result_list=[]
for i in L:
if not i[1] in i1_list:
result_list.append(i)
i1_list.append(i[1])
print(result_list)

list.append(another_list) vs list.append(another_list[:]) in python? [duplicate]

This question already has answers here:
What is the difference between shallow copy, deepcopy and normal assignment operation?
(12 answers)
Closed 7 years ago.
Here is a problem I had to do:
We are going to implement a very helpful function, called group.
group takes a list of things and returns a list of group, where each group is formed by all equal consecutive elements in the list.
For example:
group([1, 1, 1, 2, 3, 1, 1]) == [[1, 1, 1], [2], [3], [1, 1]]
group([1, 2, 1, 2, 3, 3]) == [[1], [2], [1], [2], [3, 3]]
And here is my initial solution:
def group(int_list):
group_list = []
current_list = []
for i in range(len(int_list)):
if int_list[i] not in current_list:
if len(current_list) != 0:
group_list.append(current_list)
del current_list[:]
current_list.append(int_list[i])
else:
current_list.append(int_list[i])
group_list.append(current_list)
return group_list
And the output I was getting:
[[1, 1], [1, 1], [1, 1], [1, 1]]
After spending like 30 minutes trying to figure out the problem, I changed the 9th line from group_list.append(current_list) to group_list.append(current_list[:]) and surprisingly the magic worked. I got the correct output:
[[1, 1, 1], [2], [3], [1, 1]]
So I guess my question is what's the difference between current_list and current_list[:] ?
current_list[:] is a shallow copy of current_list; e.g.,:
Introducing lists: Slicing shorthand
Python list slice syntax used for no obvious reason
"copying a list the right way"
In your function, you're building up a list (of the current group) in the thing referred to by current_list. When you're done, you add this thing to group_list, and then reset the thing by deleting all of its contents (del current_list[:]). We have to remember that everything in Python is a reference, so, using your first code, group_list contains several references to the same object (this is why your output looks like [[1, 1], [1, 1], [1, 1], [1, 1]]). When you delete the contents of current_list and add new elements later on, you do this to every element of group_list, too.
Using the current_list[:] syntax that you discovered, you create a copy of current_list and add this onto group_list; this copy is not modified later when you delete the contents of current_list.
Basicaly the main difference is that current_list is the reference to the list, and current_list[:] is a new array with the elements of the list. So, using the first one, when you change current_list, group_list is also changed. The other way if you change current_list, group_list is not modified.

How to breakup a list of list in a given way in Python [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Given a list of list of integers, task is to write a function which will output another list of list of integers. It's hard to tell the nature of the desired output in words, I am writing some examples:
# list with one element will be returned
>>> func([[1, 2, 3, 4]])
[[1, 2, 3, 4]]
>>> func([[1], [1, 2]])
[[1], [2]]
>>> func([[1, 2], [1]])
[[1], [2]]
>>> func([[1], [1, 2, 3]])
[[1], [2, 3]]
>>> func([[1], [1, 2, 3], [1, 4]])
[[1], [2, 3], [4]]
>>> func([[1, 2], [2, 3]])
[[1], [2], [3]]
>>> func([[1], [2], [1, 2, 3]])
[[1], [2], [3]]
>>> func([[1, 2], [1, 2, 3]])
[[1, 2], [3]]
>>> func([[1], [1, 2], [1, 2, 3]])
[[1], [2], [3]]
(UPDATE) You can use the following preconditions:
Each inner list contains integers already sorted and there is no duplicate entry.
The outer list has no duplicate entry.
(UPDATE) As you asked, here's what I think I'm stuck with:
This is a problem on some optimization on a Directed Graph, with numbers as nodes and inner lists as starting points of edges (the outer list is the set of starting points of all edges). Now, you might ask, "How there be multiple start points to a single edge, which is shown in some test cases?"
This is what I am trying to do: for func ([1, 2]) the node 1 & node 2 can be merged to a single node. The output [1, 2] shows that these two can be merged.
Now look at func ([[1], [1, 2]]). The 2nd inner list tries to merge node 1 & 2 together, but the 1st inner list says node 1 cannot be merged to anything. So, the output is [[1], [2]], indicating that node 1 & node 2 are to be kept separated.
For func ([[1], [2, 3], [1, 2, 3]]), node 1 is to be separated, but node 2 & 3 can be merged; so the output would be [[1], [2, 3]]
In case of func ([[1, 2], [2, 3]]), neither node 1 & 2 nor 2 & 3 can be merged as node 1 & 3 can be merged, so the expected result is [[1], [2], [3]].
There is a list of integers also, which comprises of end points of vertices, each integer corresponds to each inner list. When elements of an inner list are merged to one, there remains only 1 edge. When they are separated, there are singleton lists, and elements from each of which is taken as starting points; the list of end points are updated accordingly.
I think it will help you to realize my needs.
This relies on the list of lists being sorted in ascending length (and the outputs needs sorting), but works with all provided input as of time of posting.
def removeFromList(elementsToRemove):
def closure(list):
for element in elementsToRemove:
if list[0] != element:
return
else:
list.pop(0)
return closure
def func(listOfLists):
result = []
for i, thisList in enumerate(listOfLists):
result.append(thisList)
map(removeFromList(thisList), listOfLists[i+1:])
return result
You can remove the closure using more for loops, but it looked too ugly, and too deeply nested.
Edit: based on updates, this is the naive solution to the actual problem:
from itertools import combinations
def isSubsetOrDisjointTo(listA, listB):
return all(item in listB for item in listA) or all(item not in listB for item in listA)
def func(nodesToJoin):
#flatten list, extracting duplicates
allNodes = sorted(set(itertools.chain(*nodesToJoin)))
result = []
seen = set()
for length in xrange(max(map(len, nodesToJoin)), 0, -1):
#start with longest possible, work to shortest
for sublist in combinations(allNodes, length):
if any(item in seen for item in sublist):
#skip possible sublists with options we've already seen in the result
continue
if all(isSubsetOrDisjointTo(sublist, node) for node in nodesToJoin):
result.append(sublist)
seen.update(sublist)
return result
There are probably a number of ways this can be optimised or improved.
def func(L):
r = [L[0]]
for i in range(1, len(L)):
r.append(list(set(L[i]) - set(L[i-1])))
return r
def f (L):
return [[l for l in L[i] if l not in sum(L[:i], [])] for i in range(len(L))]
Edit: The OP keeps changing what the test results are meant to be so I dunno, this gives the correct answers for all the tests that were there when I wrote it.

Categories