Related
I have a dataset of results from games of n players, where each game has n-1 players playing. The results of a game may look like this:
1 2 _
_ 1 2
2 _ 1
where each column represents the results of 1 player. However, the dataset has been corrupted and columns where players have a bye (_) have been collapsed so that results turn out like this:
1 2 2
2 1 1
I currently have python code to take in the results from a file and add them to an numpy array, which includes a function to insert a bye into a column. Printing the array gives this output:
[['1' '2' '2']
['1' '1' '2']
['0' '0' '0']]
I am struggling to figure out how to find the corrected results, especially if some collapsed results may have multiple solutions. I know I need to use a recursive solve () function, but I'm not sure how to go about it. Here is my current source code:
import numpy as np
collapsed_results = []
p = 0
def insert_bye(grid, row, column):
for i in reversed(range(row, p)):
if i == row:
grid[i][column] = "_"
else:
grid[i][column] = grid[i - 1][column]
return grid
def solve(collapsed_results):
pass
if __name__ == "__main__":
while True:
try:
line = input()
except EOFError:
break
line = line.split(" ")
collapsed_results.append(line)
# Number of players
p = len(collapsed_results[0])
collapsed_results.append([0] * p)
collapsed_results = np.array(collapsed_results)
You can use a recursive generator function:
from collections import deque
def pad_col(d, l, c=[]):
if len(c) == l:
yield c
else:
yield from ([] if not d else pad_col(d[1:], l, c+[d[0]]))
if l - len(c) > len(d):
yield from pad_col(d, l, c+[0])
def solve(collapsed, l = 3):
def combos(d, c = []):
if not d:
yield list(zip(*c))
else:
for i in pad_col(d[0], l):
yield from combos(d[1:], c+[i])
return list(combos([*zip(*collapsed)]))
print(solve([[1, 2, 2], [2, 1, 1]]))
Output:
[[(1, 2, 2), (2, 1, 1), (0, 0, 0)], [(1, 2, 2), (2, 1, 0), (0, 0, 1)], [(1, 2, 0), (2, 1, 2), (0, 0, 1)], [(1, 2, 2), (2, 0, 1), (0, 1, 0)], [(1, 2, 2), (2, 0, 0), (0, 1, 1)], [(1, 2, 0), (2, 0, 2), (0, 1, 1)], [(1, 0, 2), (2, 2, 1), (0, 1, 0)], [(1, 0, 2), (2, 2, 0), (0, 1, 1)], [(1, 0, 0), (2, 2, 2), (0, 1, 1)], [(1, 2, 2), (0, 1, 1), (2, 0, 0)], [(1, 2, 2), (0, 1, 0), (2, 0, 1)], [(1, 2, 0), (0, 1, 2), (2, 0, 1)], [(1, 2, 2), (0, 0, 1), (2, 1, 0)], [(1, 2, 2), (0, 0, 0), (2, 1, 1)], [(1, 2, 0), (0, 0, 2), (2, 1, 1)], [(1, 0, 2), (0, 2, 1), (2, 1, 0)], [(1, 0, 2), (0, 2, 0), (2, 1, 1)], [(1, 0, 0), (0, 2, 2), (2, 1, 1)], [(0, 2, 2), (1, 1, 1), (2, 0, 0)], [(0, 2, 2), (1, 1, 0), (2, 0, 1)], [(0, 2, 0), (1, 1, 2), (2, 0, 1)], [(0, 2, 2), (1, 0, 1), (2, 1, 0)], [(0, 2, 2), (1, 0, 0), (2, 1, 1)], [(0, 2, 0), (1, 0, 2), (2, 1, 1)], [(0, 0, 2), (1, 2, 1), (2, 1, 0)], [(0, 0, 2), (1, 2, 0), (2, 1, 1)], [(0, 0, 0), (1, 2, 2), (2, 1, 1)]]
I have a dictionary {(0, 0): [(1, 0), (0, 1)], (0, 1): [(1, 1), (0, 0), (0, 2)], (0, 2): [(1, 2), (0, 1), (0, 3)], (0, 3): [(1, 3), (0, 2), (0, 4)], (0, 4): [(1, 4), (0, 3), (0, 5)], (0, 5): [(1, 5), (0, 4), (0, 6)]}, the keys are coordinates or (row, col) tuples that correlate to a matrix, the values are the neighbors or the adjacent (row, col) pairs that are near that node so for example if (0, 0) is the most top left element in the grid the nodes near it are (0, 1) and (1, 0) because they are adjacent. My question is how can I filter out this dictionary so that instead of the (row, col) tuples I'll have the elements corresponding to that position on the grid so lets say (0, 0):[(1, 0), (0, 1)] is going to be equal to my_matrix[0][0]:[my_matrix[1][0], my_matrix[0][1]] and so on for the whole dictionary
Using a dict comprehension with a nested list comprehension to loop over the neighbors:
matrix = [[i+j for i in range(10)] for j in range(10)]
d = {(0, 0): [(1, 0), (0, 1)], (0, 1): [(1, 1), (0, 0), (0, 2)], (0, 2): [(1, 2), (0, 1), (0, 3)], (0, 3): [(1, 3), (0, 2), (0, 4)], (0, 4): [(1, 4), (0, 3), (0, 5)], (0, 5): [(1, 5), (0, 4), (0, 6)]}
print({
matrix[key[0]][key[1]]:
[matrix[coord[0]][coord[1]] for coord in coords]
for key, coords in d.items()
})
Output:
{0: [1, 1], 1: [2, 0, 2], 2: [3, 1, 3], 3: [4, 2, 4], 4: [5, 3, 5], 5: [6, 4, 6]}
I am trying to generate a set of all possible combinations of {0,1} and {00,01,10,11}, which is supposed to be an array that has the shape of (16,4)
things like
[[((0,0),0), ((0,1),0), ((1,0),0), ((1,1),0)],
[((0,0),0), ((0,1),0), ((1,0),0), ((1,1),1)],
...
[((0,0),1), ((0,1),1), ((1,0),1), ((1,1),1)],
...
]]
This needs not actually be array, I misused the term array since list has no shape :)
'00' is good, (0, 0) is better, since the latter has a good looking,
Note: there is supposed to be 16 items in the outer list and 4 items in the inner list
the code could give the smallest block
bset = np.array([0,1])
fset = np.array(np.meshgrid(bset,bset)).T.reshape(-1,2)
[tuple(i) for i in fset]
which is
[(0, 0), (0, 1), (1, 0), (1, 1)]
so far, so cool, and then things get messed.
this code
np.array(np.meshgrid(t4,bset), np.object)
gives
array([[[0, 0, 0, 1, 1, 0, 1, 1],
[0, 0, 0, 1, 1, 0, 1, 1]],
[[0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1]]], dtype=object)
other than something like
[((0,0),0), ((0,1),0), ((1,0),0), ((1,1),0)]
I also tried itertools
arr = [(0, 0), (0, 1), (1, 0), (1, 1)]
list(combinations(arr, 2))
which is close
[((0, 0), (0, 1)),
((0, 0), (1, 0)),
((0, 0), (1, 1)),
((0, 1), (1, 0)),
((0, 1), (1, 1)),
((1, 0), (1, 1))]
How to fix this?
You can use itertools.product in the following way:
>>> options = (0, 1)
>>> base = list(it.product(options, options))
>>> output = [list(zip(base, i)) for i in it.product(*[options]*4)]
>>> pprint(output)
[[((0, 0), 0), ((0, 1), 0), ((1, 0), 0), ((1, 1), 0)],
[((0, 0), 0), ((0, 1), 0), ((1, 0), 0), ((1, 1), 1)],
[((0, 0), 0), ((0, 1), 0), ((1, 0), 1), ((1, 1), 0)],
[((0, 0), 0), ((0, 1), 0), ((1, 0), 1), ((1, 1), 1)],
[((0, 0), 0), ((0, 1), 1), ((1, 0), 0), ((1, 1), 0)],
[((0, 0), 0), ((0, 1), 1), ((1, 0), 0), ((1, 1), 1)],
[((0, 0), 0), ((0, 1), 1), ((1, 0), 1), ((1, 1), 0)],
[((0, 0), 0), ((0, 1), 1), ((1, 0), 1), ((1, 1), 1)],
[((0, 0), 1), ((0, 1), 0), ((1, 0), 0), ((1, 1), 0)],
[((0, 0), 1), ((0, 1), 0), ((1, 0), 0), ((1, 1), 1)],
[((0, 0), 1), ((0, 1), 0), ((1, 0), 1), ((1, 1), 0)],
[((0, 0), 1), ((0, 1), 0), ((1, 0), 1), ((1, 1), 1)],
[((0, 0), 1), ((0, 1), 1), ((1, 0), 0), ((1, 1), 0)],
[((0, 0), 1), ((0, 1), 1), ((1, 0), 0), ((1, 1), 1)],
[((0, 0), 1), ((0, 1), 1), ((1, 0), 1), ((1, 1), 0)],
[((0, 0), 1), ((0, 1), 1), ((1, 0), 1), ((1, 1), 1)]]
You can achieve this without numpy. Let's say you have two lists like this:
>>> l1 = ['0', '1']
>>> l2 = ['00','01','10','11'] # using string as your question is unclear, see below
You can use itertools.product like this:
>>> import itertools
>>> result = list(itertools.product(l1, l2))
>>> result
[('0', '00'), ('0', '01'), ('0', '10'), ('0', '11'), ('1', '00'), ('1', '01'), ('1', '10'), ('1', '11')]
itertools.product returns an iterable.
In our question your input set is {00,01,10,11} and in output you want (0, 0),.. is this some typo?
You can perform itertools.product on set too but the set you provided in your question is not valid python code.
Still your question is unclear about the inputs but I am assuming it's:
set1 = {0, 1}
set2 = {(0, 0, ), (0, 1, ), (1, 0, ), (1, 1, )} # if you have a string or something else, convert it to tuple
Then you can use something like this:
import pprint
result = [list(itertools.product(set2, [x])) for x in set1]
pprint.pprint(result)
Output:
[[((0, 1), 0), ((1, 0), 0), ((0, 0), 0), ((1, 1), 0)],
[((0, 1), 1), ((1, 0), 1), ((0, 0), 1), ((1, 1), 1)]]
Python:
How to efficiency execute a multidimensional loop, when the number of indexes to loop is dynamic.
Assume an array var_size containing the size of each variable
var_size = [ 3, 4, 5 ]
and a function 'loop' which will call 'f(current_state)' for each point.
def f(state): print state
loop(var_size, f)
This call would call f in the following order:
f( [ 0, 0, 0])
f( [ 0, 0, 1])
f( [ 0, 0, 2])
f( [ 0, 1, 0])
etc....
You can do this with itertools.product:
>>> print list(itertools.product(*(range(x) for x in reversed([3,4,5]))))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 3, 0), (0, 3, 1), (0, 3, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 3, 0), (1, 3, 1), (1, 3, 2), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0), (2, 2, 1), (2, 2, 2), (2, 3, 0), (2, 3, 1), (2, 3, 2), (3, 0, 0), (3, 0, 1), (3, 0, 2), (3, 1, 0), (3, 1, 1), (3, 1, 2), (3, 2, 0), (3, 2, 1), (3, 2, 2), (3, 3, 0), (3, 3, 1), (3, 3, 2), (4, 0, 0), (4, 0, 1), (4, 0, 2), (4, 1, 0), (4, 1, 1), (4, 1, 2), (4, 2, 0), (4, 2, 1), (4, 2, 2), (4, 3, 0), (4, 3, 1), (4, 3, 2)]
Note that I'm generating tuples instead of lists, but that's easy to fix if you really need to.
So, to me it looks like you want:
map(f,itertools.product(*map(range,reversed(var_size))))
Make a list initialized to 0s, as many entries as are in var_size. We treat this list as a list of 'tumblers' - we increment the last one in the list until it overflows its limit (aka var_size at the same point into the list). If so, we set it to 0, go one left and repeat the increment/overflow check until we either do not overflow (reset the 'which tumbler are we looking at' variable back to the last and continue) or overflow all entries of the list (we're done, we looped all the way around), then perform the next call.
I don't know if this is optimal or pythonic, but it is O(n).
This code does the job - And it has the advantage of not creating the list. However, it not that elegant....
Any ideas on how to get this better?
def loop(var_size, f):
nb = len(var_size)
state = [0]*nb
ok = True
while ok:
f(state)
for i in range(nb-1, -1, -1):
state[i] = state[i]+1
if state[i] < var_size[i]:
break
else:
if i == 0:
ok = False
break
else:
state[i] = 0
var_size = [3,4,5]
def f(state):
print state
loop(var_size, f)
n=int(raw_input('enter the number of mcnuggets you want to buy : ')) #total number of mcnuggets you want yo buy
for a in range(1,n) and b in range(1,n) and c in range(1,n) :
if (6*a+9*b+20*c==n):
print 'number of packs of 6 are ',a
print 'number of packs of 9 are ',b
print 'number of packs of 20 are',c
i am new to programming and i am learning python.the code above gives errors. Any suggestion.?.
You should use nested loops:
for a in range(1, n):
for b in range(1, n):
for c in range(1, n):
if ...
Or even better:
import itertools
for a, b, c in itertools.product(range(1, n + 1), repeat=3):
if ...
I think you should start the ranges from 0, otherwise you will only get answers that include at least one of each size. You can also make less work for the computer since you know that there will never be more than n/6 packs of 6 required etc. This can be a big saving - for 45 nuggets you only need to test 144 cases compared to 97336
from itertools import product
n=int(raw_input('enter the number of mcnuggets you want to buy : ')) #total number of mcnuggets you want to buy
for a,b,c in product(range(n//6+1), range(n//9+1), range(n//20+1)) :
if (6*a+9*b+20*c==n):
print 'number of packs of 6 are ',a
print 'number of packs of 9 are ',b
print 'number of packs of 20 are',c
itertools.product gives the cartesian product of the 3 ranges. For example
>>> from itertools import product
>>> list(product(range(3),range(4),range(5)))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), (0, 2, 4), (0, 3, 0), (0, 3, 1), (0, 3, 2), (0, 3, 3), (0, 3, 4), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 0, 4), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 3, 0), (1, 3, 1), (1, 3, 2), (1, 3, 3), (1, 3, 4), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 0, 3), (2, 0, 4), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 1, 4), (2, 2, 0), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 2, 4), (2, 3, 0), (2, 3, 1), (2, 3, 2), (2, 3, 3), (2, 3, 4)]
If you want to have values from multiple sequences in a for loop then you can use zip, for example:
for (a,b,c) in zip(xrange(1,n), xrange(1,n), xrange(1,n)) :
....
Of course it is a waste repeating the same range, but judging from the title of your post I guess that using the same range is only and example.