Enumeration of balls in basket with a specific order - python

I'd like to enumerate the solution with a specific order. Currently, with the below code:
def balls_in_baskets(balls=1, baskets=1):
if baskets == 1:
yield [balls]
elif balls == 0:
yield [0]*baskets
else:
for i in range(balls+1):
for j in balls_in_baskets(balls-i, 1):
for k in balls_in_baskets(i, baskets-1):
yield j+k
x=[t for t in balls_in_baskets(3,3)][::-1]
for i in x:
print(i)
I get this:
[0, 0, 3]
[0, 1, 2]
[0, 2, 1]
[0, 3, 0]
[1, 0, 2]
[1, 1, 1]
[1, 2, 0]
[2, 0, 1]
[2, 1, 0]
[3, 0, 0]
However, I would like this order:
[0, 0, 3]
[0, 1, 2]
[1, 0, 2]
[0, 2, 1]
[1, 1, 1]
[2, 0, 1]
[0, 3, 0]
[1, 2, 0]
[2, 1, 0]
[3, 0, 0]
How can I achieve this correct order?

You already lose the memory-efficiency of your generator by consuming it in a list comprehension so you could also sort the result:
x = sorted(balls_in_baskets(3,3), key=lambda x: x[::-1], reverse=True)
which then prints the expected output:
[0, 0, 3]
[0, 1, 2]
[1, 0, 2]
[0, 2, 1]
[1, 1, 1]
[2, 0, 1]
[0, 3, 0]
[1, 2, 0]
[2, 1, 0]
[3, 0, 0]

Related

how to compare and count number of occurrences in two list of list?

I have two different list of list, with different size (List A with size in range 1000 and list B with size in range 10,000).
A=[[0, 0, 0],
[0, 0, 1],
[0, 0, 2],
[0, 0, 3],
[0, 0, 4],
[0, 0, 5],
[0, 1, 0],
[0, 1, 1],
[0, 1, 2],
[0, 1, 3],
[0, 1, 4],
[0, 1, 5],
[0, 1, 6],
[0, 1, 7],
[0, 1, 8],
[0, 1, 9],
[0, 2, 0],
[0, 2, 1],
[0, 2, 2]]
B=[[1, 1, 2],
[0, 0, 2],
[0, 0, 1],
[4, 2, 2],
[3, 1, 2],
[1, 0, 1],
[1, 1, 2],
[0, 1, 2],
[0, 0, 0],
[2, 2, 3],
[1, 2, 1],
[0, 2, 1],
[0, 2, 0],
[0, 2, 1],
[0, 1, 3],
[0, 0, 0],
[1, 2, 5],
[0, 4, 3],
[0, 1, 3]]
I need to compare list with list B and find out how many times each element of A occur in B. For example I need to find out how many times [0,0,0] (first element of A) occur in B.
Thank you for your help.
This should work:
A = [[0, 0, 0],
[0, 0, 1],
[0, 0, 2],
[0, 0, 3],
[0, 0, 4],
[0, 0, 5],
[0, 1, 0],
[0, 1, 1],
[0, 1, 2],
[0, 1, 3],
[0, 1, 4],
[0, 1, 5],
[0, 1, 6],
[0, 1, 7],
[0, 1, 8],
[0, 1, 9],
[0, 2, 0],
[0, 2, 1],
[0, 2, 2]]
B = [[1, 1, 2],
[0, 0, 2],
[0, 0, 1],
[4, 2, 2],
[3, 1, 2],
[1, 0, 1],
[1, 1, 2],
[0, 1, 2],
[0, 0, 0],
[2, 2, 3],
[1, 2, 1],
[0, 2, 1],
[0, 2, 0],
[0, 2, 1],
[0, 1, 3],
[0, 0, 0],
[1, 2, 5],
[0, 4, 3],
[0, 1, 3]]
nums = []
for i in A:
for j in B:
if i in B:
nums.append(str(i))
nums_freq = {}
nums = list(dict.fromkeys(nums))
for i in nums:
count = 0
for j in B:
if i == str(j):
if i in nums_freq.keys():
nums_freq[i] += 1
else:
nums_freq[i] = 1
Value for num_freq:
{'[0, 0, 0]': 2,
'[0, 0, 1]': 1,
'[0, 0, 2]': 1,
'[0, 1, 2]': 1,
'[0, 1, 3]': 2,
'[0, 2, 0]': 1,
'[0, 2, 1]': 2}
>>> import operator
>>> for e in A:
... print(e, 'appearing in :', operator.countOf(B, e))
...
[0, 0, 0] appearing in : 2
[0, 0, 1] appearing in : 1
[0, 0, 2] appearing in : 1
[0, 0, 3] appearing in : 0
[0, 0, 4] appearing in : 0
[0, 0, 5] appearing in : 0
[0, 1, 0] appearing in : 0
[0, 1, 1] appearing in : 0
[0, 1, 2] appearing in : 1
[0, 1, 3] appearing in : 2
[0, 1, 4] appearing in : 0
[0, 1, 5] appearing in : 0
[0, 1, 6] appearing in : 0
[0, 1, 7] appearing in : 0
[0, 1, 8] appearing in : 0
[0, 1, 9] appearing in : 0
[0, 2, 0] appearing in : 1
[0, 2, 1] appearing in : 2
[0, 2, 2] appearing in : 0
I can suggest 2 different ways to do it:
Using a counter:
from collections import Counter
cb = Counter(tuple(b) for b in B)
list((a, cb[tuple(a)]) for a in A))
Using nested comprehensions:
list((a, sum(all(ia == ib for ia, ib in zip(a, b)) for b in B)) for a in A)
Actually, you should consider having the inner collection as tuples instead of lists, because tuples support element-wise equality and are hashable.
if A and B were lists of tuples, it would be as simple as:
Counter(a for a in A for b in B if a == b)

Most efficient way to create Tetris-like blocks

I'm trying create custom shapes using the Tetris technique. For now I have 2 approaches:
L = [['.....',
'...0.',
'.000.',
'.....',
'.....'],
['.....',
'..0..',
'..0..',
'..00.',
'.....'],
['.....',
'.....',
'.000.',
'.0...',
'.....'],
['.....',
'.00..',
'..0..',
'..0..',
'.....']]
L = [[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6, 10]]
Is there any more efficient way to create grid? Since I got more than 10 of those and I'll have to create at most 80 of nested lists(10 * 4directions * 2 mirrored)
I prefer to use matrices as follows. It will contain a list of all the rotations of a tetris block.
I_Tetromino = [
[
[1, 1, 1, 1]
],
[
[1],
[1],
[1],
[1]
]
]
J_Tetromino = [
[
[0, 1],
[0, 1],
[1, 1]
],
[
[1, 0, 0],
[1, 1, 1]
],
[
[1, 1],
[1, 0],
[1, 0]
],
[
[1, 1, 1],
[0, 0, 1]
]
]
You could make a class of block, then draw the block on the grid by its color.
Then you can render it on your screen.
This may not be the most efficient method but I prefer to use a method which is not very complicated and readable.
Edit: You can make a function also to rotate it.
def rot90(matrix):
return list(zip(*matrix[::-1]))
def rot180(matrix):
return rot90(rot90(matrix))
def rot270(matrix):
return rot90(rot180(matrix))
you could start with the basic shapes and build a list by applying rotations and flips to them and keeping only distinct resulting shapes:
def rot(M,n):
return rot(list(map(list,zip(*reversed(M)))),n-1) if n else M
L = [ [1,1,1],
[0,0,1] ]
I = [ [1,1,1,1] ]
S = [ [0,1,1],
[1,1,0] ]
T = [ [1,1,1],
[0,1,0] ]
B = [ [1,1],
[1,1] ]
blocks = [ rot(fb,r) for b in (L,I,S,T,B)
for fb in (b,b[::-1])
for r in range(4) ]
blocks = [ b for i,b in enumerate(blocks) if blocks.index(b)==i ] # distincts
output:
def printShape(M):
for r in M: print(r)
for block in blocks:
printShape(block)
print()
[1, 1, 1]
[0, 0, 1]
[0, 1]
[0, 1]
[1, 1]
[1, 0, 0]
[1, 1, 1]
[1, 1]
[1, 0]
[1, 0]
[0, 0, 1]
[1, 1, 1]
[1, 0]
[1, 0]
[1, 1]
[1, 1, 1]
[1, 0, 0]
[1, 1]
[0, 1]
[0, 1]
[1, 1, 1, 1]
[1]
[1]
[1]
[1]
[0, 1, 1]
[1, 1, 0]
[1, 0]
[1, 1]
[0, 1]
[1, 1, 0]
[0, 1, 1]
[0, 1]
[1, 1]
[1, 0]
[1, 1, 1]
[0, 1, 0]
[0, 1]
[1, 1]
[0, 1]
[0, 1, 0]
[1, 1, 1]
[1, 0]
[1, 1]
[1, 0]
[1, 1]
[1, 1]
Note that defining these blocks as variable size 2D masks should make it much easier to implement block rendering, movements and collision detection in the game later on.

All posible combinations of numbers on a list

I need to find all the possible combinations of a list with a defined length and numbers of defined size, but subject to a restriction that does not allow having the same repeated number in the list (except 0).
Currently I have a recursive code that generates all the combinations, but when trying to create the constraints I lose many options.
I have tried the options that appear commented to solve it, but it still does not work for me. Thank you in advance for your help.
size=3
l=[0 for x in range(size)]
def recursive(l, index, num, final):
if index == len(l) or num == final:
return
# if num!=0 and num in l:
# return
l[index]=num
print(l)
recursive(l, index+1, 0, final)
recursive(l, index, num+1, final)
recursive(l, 0, 0, 4)
the expected output for a list of size 3 and final number 3 would be something like this
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 2]
[0, 1, 3]
[0, 2, 0]
[0, 2, 1]
[0, 2, 3]
[0, 3, 0]
[0, 3, 1]
[0, 3, 2]
[1, 0, 0]
[1, 0, 2]
[1, 0, 3]
[1, 2, 0]
[1, 2, 3]
[1, 3, 0]
[1, 3, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 3]
[2, 1, 0]
[2, 1, 3]
[2, 3, 0]
[2, 3, 1]
[3, 0, 0]
[3, 0, 1]
[3, 0, 2]
[3, 1, 0]
[3, 1, 2]
[3, 2, 0]
[3, 2, 1]
Start with the powerset of the non-zero values (a function for computing the powerset of a list can be found in the itertools documentation.)
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
>>> list(powerset([1,2,3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
(You could compute the power set including 0, but you would still need to zero-pad the shorter elements, as well as discard (0,1,2,3)).
Each element of the powerset should next be padded with zeros so that they are all the same length.
Finally, you want the list of permutations (using itertools.permutations) of each 0-padded permutation of the original input.
Use itertools.combinations_with_replacement(), and then filter out the elements with duplicates.
def has_duplicates(l):
'''Return True if list has duplicate elements other than 0'''
l = [x in l if x != 0]
return len(l) != len(set(l))
result = [comb for comb in itertools.combinations_with_replacement(l, 3) if not has_duplicates(comb)]
You can make this lazy by using itertools.filterfalse(); this way you won't fill up memory with all combinations of a large list.
result = itertools.filterfalse(has_duplicates, itertools.combinations_with_replacement(l, 3))
Here is a solution based on counters, I am using a base 4 counter:
def charcnt(s, a):
ctr = [1 if x == a else 0 for x in s ]
return sum(ctr)
def my_range(start,end,base,step=1):
def Convert(n,base):
string = "0123"
if n < base:
return string[n]
else:
return Convert(n//base,base) + string[n%base]
return (Convert(i,base) for i in range(start,end,step))
# base-10 58 will produce base-4 321
counter = [x.zfill(3) for x in my_range(0, 58, 4)]
result = []
for s in counter:
if charcnt(s, '1') > 1 or charcnt(s, '2') > 1 or charcnt(s, '3') > 1:
continue
else:
result.append(s)
result = [[int(n) for n in list(s)] for s in result]
#print(len(result))
for i in result:
print(i)
Will produce:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 2]
[0, 1, 3]
[0, 2, 0]
[0, 2, 1]
[0, 2, 3]
[0, 3, 0]
[0, 3, 1]
[0, 3, 2]
[1, 0, 0]
[1, 0, 2]
[1, 0, 3]
[1, 2, 0]
[1, 2, 3]
[1, 3, 0]
[1, 3, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 3]
[2, 1, 0]
[2, 1, 3]
[2, 3, 0]
[2, 3, 1]
[3, 0, 0]
[3, 0, 1]
[3, 0, 2]
[3, 1, 0]
[3, 1, 2]
[3, 2, 0]
[3, 2, 1]

Python which itertools module function should I use?

Which itertools function (or any function) should I use if I want to achieve this:
Input:
arr = [0, 1, 2]
Output:
[
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 1]
[0, 1, 2]
[0, 2, 2]
[1, 1, 1]
[1, 1, 2]
[1, 2, 2]
[2, 2, 2]
]
Conditions:
Length of r/3
No combinations of e.g. 1,0,0 and 0,1,0
Yes repeating values e.g. 1,1,1 or 0,1,1
print([a for a in itertools.combinations_with_replacement(arr, 3)])

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