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.
Related
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'), ....}
I need to generate unique random lists for 3 different objects, each object can appear once on each lis and each code has to in fixed length of 5.
import random
#generate random codes
def generator(code, objects):
for i in range(len(code)):
x = random.choices(objects)
code[i] = x[0]
#Check if code is unique
def isSame(code, list):
if code not in list:
return False
else:
return True
#If code is unique, append it to the codeList and increase counter by 1
codeCount = 0
def listAppend(code, list):
if isSame(code,list) == True:
print('This code is not unique')
else:
list.append(code)
global codeCount
codeCount += 1
if __name__ == '__main__':
codeList = []
desiredCount = 12
while codeCount != desiredCount:
code = [None]*5
objects = ['a','b','c','d','e','f','g']
generator(code, objects)
listAppend(code,codeList)
print(codeList)
This gives me random unique lists but however I couldn't think of how to make each object appear only once in each unique list.
e.g. ['a', 'g', 'g', 'a', 'e'] ==> 'g' and 'a' has repeated twice where I need them to appear only once. like, ['a','b','c','d','e']
Can anyone think of a good way to do this? Thanks!!
EDIT: each code has to have fixed length of 5. Also I'm using random.choices to use its probability parameter.
The way I would do it is:
from random import randrange as rr
Alphabet="abcdefghijklmnopqrstuvwxyz"
def generate(length):
code=[]
for _ in range(length):
random_number=rr(0,len(Alphabet))
if Alphabet[random_number]not in code:
code.append(Alphabet[random_number])
return code
This generates a random element from a tuple / list / string (in my case is a string of alphabet) and checks if the element is already in the code, and if not then it will be added to the code, the length of the code is determined by a parameter.
This will generate all possible 3 unique element selections from the source.
import itertools
list(itertools.combinations('abcdefg',3))
[('a', 'b', 'c'),
('a', 'b', 'd'),
('a', 'b', 'e'),
('a', 'b', 'f'),
('a', 'b', 'g'),
('a', 'c', 'd'),
('a', 'c', 'e'),
('a', 'c', 'f'),
...
('d', 'f', 'g'),
('e', 'f', 'g')]
For size 5, it will be this list
list(itertools.combinations('abcdefg',5))
[('a', 'b', 'c', 'd', 'e'),
('a', 'b', 'c', 'd', 'f'),
('a', 'b', 'c', 'd', 'g'),
('a', 'b', 'c', 'e', 'f'),
('a', 'b', 'c', 'e', 'g'),
('a', 'b', 'c', 'f', 'g'),
('a', 'b', 'd', 'e', 'f'),
('a', 'b', 'd', 'e', 'g'),
('a', 'b', 'd', 'f', 'g'),
('a', 'b', 'e', 'f', 'g'),
('a', 'c', 'd', 'e', 'f'),
('a', 'c', 'd', 'e', 'g'),
('a', 'c', 'd', 'f', 'g'),
('a', 'c', 'e', 'f', 'g'),
('a', 'd', 'e', 'f', 'g'),
('b', 'c', 'd', 'e', 'f'),
('b', 'c', 'd', 'e', 'g'),
('b', 'c', 'd', 'f', 'g'),
('b', 'c', 'e', 'f', 'g'),
('b', 'd', 'e', 'f', 'g'),
('c', 'd', 'e', 'f', 'g')]
by only adding object.remove() line to function generator, I managed to get solution the way I wanted.
by removing whatever appended to the code list, reuse is eliminated.
#generate random codes
def generator(code, objects):
for i in range(len(code)):
x = random.choices(objects)
code[i] = x[0]
#new line
objects.remove(x[0])
I have a list of elements like so:
['x', 'a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'g', 'h', 'i', 'i', 'i', 'i']
I would like to find all the "biggest" repetitions of n elements and below and the number of times each sequence is repeated. For example, if n=3:
>>> [(['a', 'b', 'c'], 3), (['g', 'h'], 2), (['i'], 4)]
I also don't want to return (['i', 'i'], 2) since there is a longer sequence involving the element 'i'.
Here is a second condition:
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'g', 'h', 'i', 'i', 'i', 'i']
>>> [(['a', 'b', 'c'], 3), (['b', 'c'], 2), (['g', 'h'], 2), (['i'], 4)]
Overlapping of elements belonging to 2 different repetitions are accepted.
I was thinking about a solution based on sliding windows of size n and decreasing, keeping track of the already used indices but I doesn't fulfill the first condition.
Is there an efficient way of doing so?
You can create a function:
import re
def counting(x):
d = re.sub(r"(?<=(\w))(?=\1)","\n","\n".join(re.findall(r"(\w+)(?=\1)",''.join(x)))).split()
return [(list(i),d.count(i)+1)for i in set(d)]
Now you can run this function on your data:
m = ['x', 'a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'g', 'h', 'i', 'i', 'i', 'i']
counting(m)
[(['g', 'h'], 2), (['i'], 4), (['a', 'b', 'c'], 3)]
n = ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'g', 'h', 'i', 'i', 'i', 'i']
counting(n)
[(['g', 'h'], 2), (['i'], 4), (['a', 'b', 'c'], 3), (['b', 'c'], 2)]
You can use a regex:
>>> li=['x', 'a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'g', 'h', 'i', 'i', 'i', 'i']
>>> [(t[0],''.join(t).count(t[0])) for t in re.findall(r'(\w+)(\1+)', ''.join(li))]
[('abc', 3), ('gh', 2), ('ii', 2)]
Or,
>>> [(list(t[0]),''.join(t).count(t[0])) for t in re.findall(r'(\w+)(\1+)', ''.join(li))
[(['a', 'b', 'c'], 3), (['g', 'h'], 2), (['i', 'i'], 2)]
I have only recently started learning Python, and I have looked at similar questions and cannot seem to find an example that helps - I have this list of tuples currently:
[('E', ['E', 'F', 'C', 'C']), ('F', ['A', 'D', 'D', 'B']), ('I', ['F', 'D', 'F', 'D']), ('R', ['E', 'B', 'D', 'B']), ('S', ['B', 'C', 'C', 'D'])]
and I want to split them up into a list of strings, so that they look like this:
['EFCC', 'ADDB', 'FDFD', 'EBDB', 'BCCD']
I have tried to use the '.join' function for this, as shown below:
stringList = "".join([str(x[1]) for x in sortedList])
but this provides me with a list in the form:
['B', 'D', 'E', 'C']['B', 'C', 'B', 'D']['E', 'C', 'D', 'C']['B', 'C', 'D', 'C']['C', 'E', 'F', 'A']
I think I am using the join method wrong, but after changing a few bits about in it, I can't figure out how to get the format I want.
Your problem is str(x[1]).
x[1] is a list, and you convert it to a string:
>>> x = ('E', ['E', 'F', 'C', 'C'])
>>> x[1]
['E', 'F', 'C', 'C']
>>> str(x[1])
"['E', 'F', 'C', 'C']"
What you want is to join the elements of the list:
>>> ''.join(x[1])
'EFCC'
So your code would become:
[''.join(x[1]) for x in sortedList]
Use a list comprehension and join the strings, like so.
t = [('E', ['E', 'F', 'C', 'C']), ('F', ['A', 'D', 'D', 'B']), ('I', ['F', 'D', 'F', 'D']), ('R', ['E', 'B', 'D', 'B']), ('S', ['B', 'C', 'C', 'D'])]
x = [''.join(b) for a, b in t]
print(x)
You can use map:
print map(lambda x: "".join(x[1]),t)
Output:
['EFCC', 'ADDB', 'FDFD', 'EBDB', 'BCCD']
My data look like this:
data = [['A', 'B', 'C', 'D'],
['E', 'F', 'G'],
['I', 'J']]
I would like to transform the data to the following:
data = [['A', 'B'],
['A', 'C'],
['A', 'D'],
['B', 'C'],
['B', 'D'],
['C', 'D'],
['E', 'F'],
['E', 'G'],
['F', 'G'],
['I', 'J']]
My codes are not working:
for item in data:
count = len(item)
for i in range (0, count):
print item[i], item[i+1]
These codes need improvement. Any suggestion?
The main thing here is to use itertools.combinations() with each item of the list. See this example below
>>> from itertools import combinations
>>> list(combinations(['A', 'B', 'C', 'D'] , 2))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
It's fairly easy to then combine the results into a single list using a list comprehension or chain.from_iterable()
>>> data = [['A', 'B', 'C', 'D'],
... ['E', 'F', 'G'],
... ['I', 'J']]
>>> list(chain.from_iterable(combinations(x, 2) for x in data))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D'), ('E', 'F'), ('E', 'G'), ('F', 'G'), ('I', 'J')]
As pointed out you can use itertool.combinations in combination with a list comprehension to flatten the list:
>>> from itertools import combinations
>>> [x for d in data for x in combinations(d, 2)]
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'),
('C', 'D'), ('E', 'F'), ('E', 'G'), ('F', 'G'), ('I', 'J')]
You can use itertools.combinations:
from itertools import combinations
data = [['A', 'B', 'C', 'D'],
['E', 'F', 'G'],
['I', 'J']]
result = []
for sublist in data:
result.extend(map(list, combinations(sublist, 2)))
print result
OUTPUT
[['A', 'B'], ['A', 'C'], ['A', 'D'], ['B', 'C'], ['B', 'D'], ['C', 'D'], ['E', 'F'], ['E', 'G'], ['F', 'G'], ['I', 'J']]
You simply need 3 nested for loops
data2 = []
for item in data:
for i in range(0, len(item)-1):
for j in range(i+1, len(item)):
data2.append([item[i],item[j]])
print data2
Output:
[['A', 'B'], ['A', 'C'], ['A', 'D'], ['B', 'C'], ['B', 'D'], ['C', 'D'],
['E', 'F'], ['E', 'G'], ['F', 'G'], ['I', 'J']]
Here is a python one liner
pairs = [ [item[i], item[j]] for item in data for i in range(len(item)) for j in range(i + 1, len(item))]