script to determine a list of distribution patterns - python

I'm working on a card game design and am struggle to get some information.
I have 8 spaces and three "objects" R, B, and G. I want to get a list of all possible distributions where there are 3 of two of the objects and 2 of the third.
Ex:
r,b,r,g,r,b,g,b
b,b,g,g,r,g,r,r
etc.

Seems like you are searching for all distinct subests of the string "RRRGGGBBB" which have a length of 8, including shuffles.
So this code probably gives you what you want-
import itertools
set(itertools.permutations("RGB" * 3, 8))
result-
{('G', 'B', 'R', 'G', 'B', 'R', 'G', 'B'),
('R', 'B', 'R', 'G', 'B', 'R', 'G', 'B'),
('R', 'G', 'B', 'G', 'B', 'R', 'G', 'B'),
('R', 'G', 'B', 'R', 'B', 'R', 'G', 'B'),
('R', 'G', 'B', 'R', 'G', 'B', 'G', 'B'),
('R', 'G', 'B', 'R', 'G', 'B', 'R', 'B'),
('R', 'G', 'B', 'R', 'G', 'B', 'R', 'G'),
('R', 'G', 'B', 'R', 'G', 'R', 'G', 'B'),
('R', 'G', 'R', 'G', 'B', 'R', 'G', 'B'), ....}

Related

Can I pause itertools on python, and resume later?

I need to create a list of strings with all the possible combinations of all letters uppercase and lowercase, with non repeating characters, of lenght 14, this is massive and I know it will take a lot of time and space.
My code right now is this:
import itertools
filename = open("strings.txt", "w")
for com in itertools.permutations('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 14):
filename.write("\n"+"1_"+"".join(com)+"\n"+"0_"+"".join(com))
print ("".join(com))
pretty basic, it does the job and I have not found a faster way as of yet (tried a java algorithm I found that seemed faster but python was faster)
Since this will take a long time, from time to time I need to turn off my computer, so I need to be able to save somewhere where I left and continue, else I will start from the beginning each time it crashes/turn off my pc / anything happen.
Is there any way to do that?
You can pickle that iterator object. Its internal state will be stored in the pickle file. When you resume it should start from where it left off.
Something like this:
import itertools
import os
import pickle
import time
# if the iterator was saved, load it
if os.path.exists('saved_iter.pkl'):
with open('saved_iter.pkl', 'rb') as f:
iterator = pickle.load(f)
# otherwise recreate it
else:
iterator = itertools.permutations('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 14)
try:
for com in iterator:
# process the object from the iterator
print(com)
time.sleep(1.0)
except KeyboardInterrupt:
# if the script is about to exit, save the iterator state
with open('saved_iter.pkl', 'wb') as f:
pickle.dump(iterator, f)
Which results in:
>python so_test.py
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n')
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'o')
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'p')
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'q')
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'r')
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 's')
>python so_test.py
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 't')
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'u')
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'v')
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'w')

How to use dictionary

How do I make 2d lists in run time when user inputs some number.
There are easy and difficult things:
horizontal ist trivial - simply join the inner list and replace the word and the word reversed by its upper case representation, then split the string into letters
vertical is mildly more difficult, but you can handle it by transposing the matrix via zip and after replacing transpose again
vertical is handled in the linked question Find Letter of Words in a Matrix Diagonally
Here is how to do horizontal and vertical:
data = [['l', 'd', 'l', 'o', 'h', 'p'],
['i', 't', 'i', 'f', 'w', 'f'],
['g', 'n', 'r', 'k', 'q', 'u'],
['h', 'g', 'u', 'a', 'l', 'l'],
['t', 'c', 'v', 'g', 't', 'l'],
['d', 'r', 'a', 'w', 'c', 's']]
words = ['draw', 'full', 'hold', 'laugh', 'light', 'start', 'all', 'kid']
from pprint import pprint as p
for w in words:
print()
# horizontal
data1 = [list(''.join(line).replace(w,w.upper())) for line in data]
# horizontal, word reversed
data1 = [list(''.join(line).replace(w[::-1],w[::-1].upper())) for line in data1]
# vertical
data1 = list(zip(*[list(''.join(line).replace(w,w.upper()))
for line in zip(*data1)]))
# vertical, word reversed
data1 = list(zip(*[list(''.join(line).replace(w[::-1],w[::-1].upper()))
for line in zip(*data1)]))
if data1 != data:
print(f"Found: {w}:")
data = data1
p(data)
else:
print(f"No {w} - check diagonally")
Output:
Found: draw:
[('l', 'd', 'l', 'o', 'h', 'p'),
('i', 't', 'i', 'f', 'w', 'f'),
('g', 'n', 'r', 'k', 'q', 'u'),
('h', 'g', 'u', 'a', 'l', 'l'),
('t', 'c', 'v', 'g', 't', 'l'),
('D', 'R', 'A', 'W', 'c', 's')]
Found: full:
[('l', 'd', 'l', 'o', 'h', 'p'),
('i', 't', 'i', 'f', 'w', 'F'),
('g', 'n', 'r', 'k', 'q', 'U'),
('h', 'g', 'u', 'a', 'l', 'L'),
('t', 'c', 'v', 'g', 't', 'L'),
('D', 'R', 'A', 'W', 'c', 's')]
Found: hold:
[('l', 'D', 'L', 'O', 'H', 'p'),
('i', 't', 'i', 'f', 'w', 'F'),
('g', 'n', 'r', 'k', 'q', 'U'),
('h', 'g', 'u', 'a', 'l', 'L'),
('t', 'c', 'v', 'g', 't', 'L'),
('D', 'R', 'A', 'W', 'c', 's')]
Found: laugh:
[('l', 'D', 'L', 'O', 'H', 'p'),
('i', 't', 'i', 'f', 'w', 'F'),
('g', 'n', 'r', 'k', 'q', 'U'),
('H', 'G', 'U', 'A', 'L', 'L'),
('t', 'c', 'v', 'g', 't', 'L'),
('D', 'R', 'A', 'W', 'c', 's')]
No light - check diagonally
No start - check diagonally
No all - check diagonally
No kid - check diagonally
For horizontal you can use this:
>>> for i in range(len(l)):# l is the list
temp = ''.join(l[i])
x = temp.find(word) #word is the user input eg. draw
y = len(word)
if x != -1:
for j in range(y):
l[i][j]=l[i][j].capitalize()
I'll try to make for vertical and diagonal as well
this one:
l = [['l', 'd', 'l', 'o', 'h', 'p'],
['i', 't', 'i', 'f', 'w', 'f'],
['g', 'n', 'r', 'k', 'q', 'u'],
['h', 'g', 'u', 'a', 'l', 'l'],
['t', 'c', 'v', 'g', 't', 'l'],
['d', 'r', 'a', 'w', 'c', 's']]
word = input("Please enter a word: ")
for i in range(len(l)):
for j in range(len(l[i])):
if l[i][j] in word:
l[i][j]=l[i][j].capitalize()
print(l)
outs:
Please enter a word: hello
[['L', 'd', 'L', 'O', 'H', 'p'], ['i', 't', 'i', 'f', 'w', 'f'], ['g', 'n', 'r', 'k', 'q', 'u'], ['H', 'g', 'u', 'a', 'L', 'L'], ['t', 'c', 'v', 'g', 't', 'L'], ['d', 'r', 'a', 'w', 'c', 's']]

mapping list of numbers to dictionary keys with multiple values

I will start with an example. let's say I have a dictionary such as:
d = {1:['A','B'],
2:['C']}
and a list:
vals = [1,2]
I want to map these values in the list (vals) to all possible ones in the dictionary (d). so the output here should be two lists such as:
[[ 'A','C']['B','C']]
this is basically the problem I am facing now. I thought I can do it with for loop but when we faced this dictionary and list of values,I couldn't do it using a for loop or even a nested loops:
d = {1:['A','B','C'] ,
2:['D','E'],
3:['F','G'],
4:['I'] }
values = [1,2,3,4]
the output here should be:
[['A', 'D', 'F', 'I'],
['A', 'D', 'G', 'I'],
['A', 'E', 'F', 'I'],
['A', 'E', 'G', 'I'],
['B', 'D', 'F', 'I'],
['B', 'D', 'G', 'I'],
['B', 'E', 'F', 'I'],
['B', 'E', 'G', 'I'],
['C', 'D', 'F', 'I'],
['C', 'D', 'G', 'I'],
['C', 'E', 'F', 'I'],
['C', 'E', 'G', 'I']]
You can use itertools product() for this. Just make a comprehension of the indexes you want to include and pass them to product(). If you are okay with tuples it's a nice one-liner:
import itertools
list(itertools.product(*(d[x] for x in values)))
results:
[('A', 'D', 'F', 'I'),
('A', 'D', 'G', 'I'),
('A', 'E', 'F', 'I'),
('A', 'E', 'G', 'I'),
('B', 'D', 'F', 'I'),
('B', 'D', 'G', 'I'),
('B', 'E', 'F', 'I'),
('B', 'E', 'G', 'I'),
('C', 'D', 'F', 'I'),
('C', 'D', 'G', 'I'),
('C', 'E', 'F', 'I'),
('C', 'E', 'G', 'I')]
If you simple need working solution, use that of Mark Meyer, however if you are curious if it is doable via fors, answer is yes, following way:
d = {1:['A','B','C'] ,2:['D','E'],3:['F','G'],4:['I']}
for k in sorted(d.keys())[:-1][::-1]:
d[k] = [(i+j) for i in d[k] for j in d[k+1]]
out = [tuple(i) for i in d[1]]
print(out)
gives:
[('A', 'D', 'F', 'I'), ('A', 'D', 'G', 'I'), ('A', 'E', 'F', 'I'), ('A', 'E', 'G', 'I'), ('B', 'D', 'F', 'I'), ('B', 'D', 'G', 'I'), ('B', 'E', 'F', 'I'), ('B', 'E', 'G', 'I'), ('C', 'D', 'F', 'I'), ('C', 'D', 'G', 'I'), ('C', 'E', 'F', 'I'), ('C', 'E', 'G', 'I')]
Note that this solution assumes that dict d is correct, i.e. its keys are subsequent numbers starting at 1 and all values are lists of one-letter strs. Now explanation: outer for is working on numbers from second greatest to 1, descending, in this particular case: 3,2,1. List comprehension is making "every-with-every" join (like SQL CROSS JOIN) of k-th list with (k+1)-th list and is effect is stored under current key k.
Finally I retrieve d[1] which is list of strs and convert it to list of tuples compliant with requirements. If how this solution is working explanation is unclear for you please copy code snippet, add print(d) below d[k] = ... and observe what it prints.

Flattening lists containing 2-tuples and 1-tuples by splitting the 2-tuples

I'm having trouble with making lists like
[['G', 'U'], ['G', 'U'], 'R', 'G']
into all the possible combinations like the following
[['G', 'G', 'R', 'G'],
['G', 'U', 'R', 'G'],
['U', 'G', 'R', 'G'],
['U', 'U', 'R', 'G']]
in Python. How do I go about it?
You can use itertools.product():
lst = [['G', 'U'], ['G', 'U'], 'R', 'G']
from itertools import product
[x for x in product(*lst)]
#[('G', 'G', 'R', 'G'),
# ('G', 'U', 'R', 'G'),
# ('U', 'G', 'R', 'G'),
# ('U', 'U', 'R', 'G')]
You can easily do this using itertools.product. It does exactly what you describe.
>> import itertools
>> l = [['G', 'U'], ['G', 'U'], 'R', 'G']
>> i = itertools.product(*l)
>> list(i)
[('G', 'G', 'R', 'G'), ('G', 'U', 'R', 'G'), ('U', 'G', 'R', 'G'), ('U', 'U', 'R', 'G')]

Python - Permutation/Combination column-wise

I have a list
mylist = [
['f', 'l', 'a', 'd', 'l', 'f', 'k'],
['g', 'm', 'b', 'b', 'k', 'g', 'l'],
['h', 'n', 'c', 'a', 'm', 'j', 'o'],
['i', 'o', 'd', 'c', 'n', 'i', 'm'],
['j', 'p', 'e', 'e', 'o', 'h', 'n'],
]
I want do permutation/combination column-wise, such the elements of the column are restricted to that column i.e., f,g,h,i,j remain in Column 1, l,m,n,o,p remain in Column 2 and so on, in the results of permutation/combination. How can this be achieved in Python 2.7?
You could use zip(*mylist) to list the "columns" of mylist. Then use the * operator (again) to unpack those lists as arguments to IT.product or IT.combinations. For example,
import itertools as IT
list(IT.product(*zip(*mylist)))
yields
[('f', 'l', 'a', 'd', 'l', 'f', 'k'),
('f', 'l', 'a', 'd', 'l', 'f', 'l'),
('f', 'l', 'a', 'd', 'l', 'f', 'o'),
('f', 'l', 'a', 'd', 'l', 'f', 'm'),
...]

Categories

Resources