Python: using append within recursive function - overwrites previous elements - python

Could someone explain how to fix the below? I've read some explanations, but couldn't get my head around it...
Many thanks in advance!
k = 2 # number of possible values for each element, in this case 0 or 1
length = 3 # length of list
result = [0] * length # initialise list
results = []
# generate permutations of list
def permutations(i, k, length):
j = 0
while j < k:
result[i] = j
if i == length - 1:
print("Result: ", result)
results.append(result)
print("Results: ", results)
else:
permutations(i + 1, k, length)
j += 1
permutations(0, k, length)
Below the output. The problem is that all previous elements in the list are overwritten...
Result: [0, 0, 0]
Results: [[0, 0, 0]]
Result: [0, 0, 1]
Results: [[0, 0, 1], [0, 0, 1]]
Result: [0, 1, 0]
Results: [[0, 1, 0], [0, 1, 0], [0, 1, 0]]
Result: [0, 1, 1]
Results: [[0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1]]
Result: [1, 0, 0]
Results: [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]
Result: [1, 0, 1]
Results: [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]]
Result: [1, 1, 0]
Results: [[1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0]]
Result: [1, 1, 1]
Results: [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]

You are appending the same list everytime. Modifying the list via that reference will propagate changes to every where the list object lives; it is the same list.
You should append a shallow copy instead, so the reference result only modifies the current list:
...
results.append(result[:])
Otherwise, you could create a new list object at the start of the function so each recursive call gets its own list:
def permutations(i, k, length):
result = []
...

I believe changing results.append(result) to result.append(result[:]) should fix the problem. It is because of the mutability of lists

What you implement can be described as repeated permutations or cartesian product.
There are k ** length lists or tuples that can be generated this way.
As with any combination, permutation or product, itertools can help you :
from itertools import product
k = 2 # number of possible values for each element, in this case 0 or 1
length = 3 # length of list
print(list(product(range(k), repeat=length)))
#[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
Done!

Related

Change randomly half of the values of list

I'm working on 2D list on python and try to hide some values from the grid:
Imagine this is the grid:
[[0, 0, 1, 1],
[0, 1, 0, 1],
[1, 0, 1, 0],
[1, 1, 0, 0]]
the result I'm getting with this code:
def startingArray(self,grid_copy):
for i in range (len(grid_copy)):
n= self.CELL
if n>len(grid_copy):
grid_copy[i]=[2 for i in grid_copy]
else:
for i in range(n):
position=random.randrange(0,len(grid_copy[i]))
grid_copy[i][position]= 2
[[2, 0, 1, 2],
[2, 2, 2, 1],
[2, 0, 2, 2],
[2, 1, 2, 2]]
it's fine but, I want something where can hide exactly the half of the values randomly?
Any ideas?
Try this
def startingArray(self,grid_copy):
for row in grid_copy:
prevItems = []
for i in range(len(row)/2+1):
if (i not in prevItems):
row[random.randint(0, len(row) - 1)] = 2
prevItems.append(i)
I didn't try this. But I think this will do what you expect.

Python 3.6 Create mapping from an array with sizes

Task
I have an array with sizes
sizes = [5, 3, 1, 2]
and based on the sizes I want to create the following array
mapping = [0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3]
Solution
My first attempt
mapping = []
ctr = 0
for i in range(len(sizes)):
for j in range(sizes[i]):
mapping.append(i)
ctr += 1
Shorter version
mapping = [[i for _ in range(sizes[i])] for i in range(len(sizes))]
mapping = list(itertools.chain(*mapping))
Question
One line version?
Is it possible to do it in just one line with a neat code?
Using enumerate
Ex:
sizes = [5, 3, 1, 2]
result = [i for i, v in enumerate(sizes) for _ in range(v)]
print(result)
Output:
[0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3]
Another approach would be to multiply the indices into sublists [[0, 0, 0, 0, 0], [1, 1, 1], [2], [3, 3]]
then flatten the result with itertoo.chain.from_iterable:
>>> from itertools import chain
>>> sizes = [5, 3, 1, 2]
>>> list(chain.from_iterable([i] * x for i, x in enumerate(sizes)))
[0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3]

Trying to print multiple text in same line with append method but outputs are different [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 years ago.
Trying to print possible number combinations in single line as list but the list have wrong output. My output is like this:
[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]
When it should be like this:
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[1, 0, 0]
[1, 0, 1]
[1, 1, 0]
[1, 1, 1]
My code is
if __name__ == '__main__':
x = 1
y = 1
z = 1
kordinat = ["x","y","z"]
result = []
for xx in range(x+1):
kordinat[0] = xx
for yy in range(y+1):
kordinat[1] = yy
for zz in range(z+1):
kordinat[2]= zz
print(kordinat)
result.append(kordinat)
print(result)
You should take itertools.product():
from itertools import product
result = list(product(range(2), repeat=3))
print(result)
# [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
EDIT:
This does not explain, why you end up having a list full of [1, 1, 1] elements. The reason can be found here. Through all your iterations, you work with a list called koordinat. When you append this to your overall list result, you append a reference to the very same object all the time. So you will have a list full of references to the same list koordinat. So changing koordinat to [1, 1, 1] in the last iteration, will change all references in your result list to this value as well. This can best be seen, when you print result after each append()
change this line:
result.append(kordinat)
to
result.append(kordinat.copy())
list is passed or assigned as reference so if you change the value it'll change everywhere.
If you want all the possible combinations of 0,1 of size 3, use combinations from itertools and call it as combinations([0,1],3). This will give you all the possible combinations you are expecting
To print elements of list in new line use pprint as below,
>>> from pprint import pprint as pp
>>> pp(result)
[[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]]
Edit-1:
Assuming, you are trying to find the binary numbers of the sequence. In your example, it is from 0-7(1-byte or 8-bits).
Try this,
>>> result = [[int(j) for j in "{0:03b}".format(i)] for i in range(8)]
>>> pp(result)
[[0, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 1],
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[1, 1, 1]]

Get all permutations that pad a list with zeroes

I have a list ls of length n and want to get all lists of length m (where m > n) that contain ls in the same order, plus (m - n) zeroes, inserted at each possible combination of positions.
For example: ls = [1, 2, 3] and m = 4 should return
[[1, 2, 3, 0],
[1, 2, 0, 3],
[1, 0, 2, 3],
[0, 1, 2, 3]]
and ls = [1, 2, 3] and m = 5 should return
[[1, 2, 3, 0, 0],
[1, 2, 0, 3, 0],
[1, 2, 0, 0, 3],
[1, 0, 2, 3, 0],
[1, 0, 2, 0, 3],
[1, 0, 0, 2, 3],
[0, 1, 2, 3, 0],
[0, 1, 2, 0, 3],
[0, 1, 0, 2, 3],
[0, 0, 1, 2, 3]]
The solution should be fast and memory efficient - in particular, it should avoid generating duplicate solutions. Any help is appreciated!
A working (but inefficient) attempt:
ls = [1, 2, 3]
m = 4
from itertools import permutations
n = len(ls)
results = []
for t in set(permutations('1' * n + '0' * (m - n))):
idxs = [i for i, j in enumerate(t) if j == '1']
result = [0] * m
for idx, value in zip(idxs, ls):
result[idx] = value
results.append(result)
Use itertools.combinations to generate every combination of places to insert zeroes. Then use a list comprehension to select 0 or the next original element to build the new list.
# Pad list orig with zeroes, out to "m" total elements.
from itertools import combinations
orig = [1, 2, 3]
m = 5
n = len(orig)
padded = []
for pad_idx in combinations(range(m), m-n):
t = orig[:]
padded.append( [0 if i in pad_idx else t.pop(0)
for i in range(m)] )
print(padded)
Output (formatted for readability):
[[0, 0, 1, 2, 3],
[0, 1, 0, 2, 3],
[0, 1, 2, 0, 3],
[0, 1, 2, 3, 0],
[1, 0, 0, 2, 3],
[1, 0, 2, 0, 3],
[1, 0, 2, 3, 0],
[1, 2, 0, 0, 3],
[1, 2, 0, 3, 0],
[1, 2, 3, 0, 0]]

How can I count duplicates in a nested list based on first two elements in python

I have a list in the form:
lst = [[1, 0, 0, 0], [1, 1, 0, 0], [2, 0, 0, 0], [2, 1, 0, 0], [2, 1, 0, 0], [1, 1, 0, 0], [3, 1, 0, 0], [1, 3, 0, 0], [2, 1, 0, 0], [2, 0, 0, 0]]
However the last two sub-elements will always be zero at the start so it could be like:
lst = [[1, 0], [1, 1], [2, 0], [2, 1], [2, 1], [1, 1], [3, 1], [1, 3], [2, 1], [2, 0]]
If that is easier.
What I want is to remove and count the duplicates of this list and set the 3rd sub-element to the count so if we take the above I want:
lst = [[1, 0, 1, 0], [1, 1, 2, 0], [2, 0, 2, 0], [2, 1, 3, 0], [3, 1, 1, 0], [1, 3, 1, 0]]
I have found explanations of how to remove duplicates at:
Removing Duplicates from Nested List Based on First 2 Elements
and
Removing duplicates from list of lists in Python
but I don't know how to count the duplicates. The order of the elements in the overall list doesn't matter but the order of the elements in the sub-lists must be preserved as [1,3] and [3,1] aren't the same thing.
If this turns out to be a dead end I could do something like hash the first two elements for counting but only if I could get them back after counting.
Any help is appreciated.
Sorry for dyslexia!
For example:
lst = [[1, 0, 0, 0], [1, 1, 0, 0], [2, 0, 0, 0], [2, 1, 0, 0], [2, 1, 0, 0], [1, 1, 0, 0], [3, 1, 0, 0], [1, 3, 0, 0], [2, 1, 0, 0], [2, 0, 0, 0]]
from collections import Counter
c = Counter(tuple(i) for i in lst)
print [list(item[0][0:2] + (item[1], 0)) for item in c.items()]
# [[1, 0, 1, 0], [1, 1, 2, 0], [3, 1, 1, 0], [2, 1, 3, 0], [1, 3, 1, 0], [2, 0, 2, 0]]
To elaborate on the great hint provided by njzk2:
Turn your list of lists into a list of tuples
Create a Counter from it
Get a dict from the Counter
Set the 3rd element of the sublists to the frequency from the Counter
from collections import Counter
lst = [[1, 0, 0, 0], [1, 1, 0, 0], [2, 0, 0, 0], [2, 1, 0, 0], [2, 1, 0, 0], [1, 1, 0, 0], [3, 1, 0, 0], [1, 3, 0, 0], [2, 1, 0, 0], [2, 0, 0, 0]]
list_of_tuples = [tuple(elem) for elem in lst]
dct = dict(Counter(list_of_tuples))
lst = [list(e) for e in dct]
for elem in lst:
elem[2] = dct[tuple(elem)]
Edit: removed duplicates with the line before the for loop. Didn't see that requirement before.
You can do this to keep count of the duplicates:
lst = [[1, 0], [1, 1], [2, 0], [2, 1], [2, 1], [1, 1], [3, 1], [1, 3], [2, 1], [2, 0]]
for x in lst:
count = 1
tmpLst = list(lst)
tmpLst.remove(x)
for y in tmpLst:
if x[0] == y[0] and x[1] == y[1]:
count = count + 1
x.append(count)
#x.append(0) #if you want to add that 4th element
print lst
Result:
[[1, 0, 1], [1, 1, 2], [2, 0, 2], [2, 1, 3], [2, 1, 3], [1, 1, 2], [3, 1, 1], [1, 3, 1], [2, 1, 3], [2, 0, 2]]
Then you can take lst and remove duplicates as mentioned in the link you posted.
A different (maybe functional) approach.
lst = [[1, 0, 0, 0], [1, 1, 0, 0], [2, 0, 0, 0], [2, 1, 0, 0],\
[2, 1, 0, 0], [1, 1, 0, 0], [3, 1, 0, 0], [1, 3, 0, 0],\
[2, 1, 0, 0], [2, 0, 0, 0]]
def rec_counter(lst):
# Inner method that is called at the end. Receives a
# list, the current element to be compared and an accumulator
# that will contain the result.
def counter(lst, elem, acc):
new_lst = [x for x in lst if x != elem]
elem[2] = lst.count(elem)
acc.append(elem)
if len(new_lst) == 0:
return acc
else:
return counter(new_lst, new_lst[0], acc)
# This part starts the recursion of the inner method. If the list
# is empty, nothing to do. Otherwise, count starting with the first
# element of the list and an empty accumulator.
if len(lst) == 0:
return []
else:
return counter(lst, lst[0], [])
print rec_counter(lst)
# [[1, 0, 1, 0], [1, 1, 2, 0], [2, 0, 2, 0], \
# [2, 1, 3, 0], [3, 1, 1, 0], [1, 3, 1, 0]]

Categories