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))]
Related
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 those python lists :
x = [('D', 'F'), ('A', 'D'), ('B', 'G'), ('B', 'C'), ('A', 'B')]
priority_list = ['A', 'B', 'C', 'D', 'F', 'G'] # Ordered from highest to lowest priority
How can I, for each tuple in my list, keep the value with the highest priority according to priority_list? The result would be :
['D', 'A', 'B', 'B', 'A']
Another examples:
x = [('B', 'D'), ('E', 'A'), ('B', 'A'), ('D', 'F'), ('E', 'C')]
priority_list = ['A', 'B', 'C', 'D', 'E', 'F']
# Result:
['B', 'A', 'A', 'D', 'C']
x = [('B', 'C'), ('F', 'E'), ('B', 'A'), ('D', 'F'), ('E', 'C')]
priority_list = ['F', 'E', 'D', 'C', 'B', 'A'] # Notice the change in priorities
# Result:
['C', 'F', 'B', 'F', 'E']
Thanks in advance, I might be over complicating this.
You can try
[sorted(i, key=priority_list.index)[0] for i in x]
though it will throw an exception if you find a value not in the priority list.
You can try:
def get_priority_val(data, priority_list):
for single_val in priority_list:
if single_val in data:
return single_val
x = [('D', 'F'), ('A', 'D'), ('B', 'G'), ('B', 'C'), ('A', 'B')]
priority_list = ['A', 'B', 'C', 'D', 'F', 'G']
final_data = []
for data in x:
final_data.append(get_priority_val(data, priority_list))
print(final_data)
Output:
['D', 'A', 'B', 'B', 'A']
you can try using list comprehension:
ans = [d[0] if priority_list.index(d[0]) < priority_list.index(d[1] ) else d[1] for d in x ]
output:
['D', 'A', 'B', 'B', 'A']
You can do it in one line using a list comprehension :
[y[0] if priority_list.index(y[0]) < priority_list.index(y[1]) else y[1] for y in x]
Output :
['D', 'A', 'B', 'B', 'A']
You can create a dict containing priority values and just use min with a custom key
>>> priority_dict = {k:i for i,k in enumerate(priority_list)}
>>> [min(t, key=priority_dict.get) for t in x]
['D', 'A', 'B', 'B', 'A']
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.
Given a dict of vocabulary: {'A': 3, 'B': 4, 'C': 5, 'AB':6} and a sentence, which should be segmented: ABCAB.
I need to create all possible combinations of this sentence such as
[['A', 'B', 'C', 'A', 'B'], ['A', 'B', 'C', 'AB'], ['AB', 'C', 'AB'], ['AB', 'C', 'A', 'B']]
That's what I have:
def find_words(sentence):
for i in range(len(sentence)):
for word_length in range(1, max_word_length + 1):
word = sentence[i:i+word_length]
print(word)
if word not in test_dict:
continue
if i + word_length <= len(sentence):
if word.startswith(sentence[0]) and word not in words and word not in ''.join(words):
words.append(word)
else:
continue
next_position = i + word_length
if next_position >= len(sentence):
continue
else:
find_ngrams(sentence[next_position:])
return words
But it returns me only one list.
I was also looking for something useful in itertools but I couldn't find anything obviously useful. Might've missed it, though.
Try all possible prefixes and recursively do the same for the rest of the sentence.
VOC = {'A', 'B', 'C', 'AB'} # could be a dict
def parse(snt):
if snt == '':
yield []
for w in VOC:
if snt.startswith(w):
for rest in parse(snt[len(w):]):
yield [w] + rest
print(list(parse('ABCAB')))
# [['AB', 'C', 'AB'], ['AB', 'C', 'A', 'B'],
# ['A', 'B', 'C', 'AB'], ['A', 'B', 'C', 'A', 'B']]
Although not the most efficient solution, this should work:
from itertools import product
dic = {'A': 3, 'B': 4, 'C': 5, 'AB': 6}
choices = list(dic.keys())
prod = []
for a in range(1, len(choices)+2):
prod = prod + list(product(choices, repeat=a))
result = list(filter(lambda x: ''.join(x) == ''.join(choices), prod))
print(result)
# prints [('AB', 'C', 'AB'), ('A', 'B', 'C', 'AB'), ('AB', 'C', 'A', 'B'), ('A', 'B', 'C', 'A', 'B')]
Use itertools permutations to give all unique combinations.
d ={'A': 3, 'B': 4, 'C': 5, 'AB':6}
l = [k for k, v in d.items()]
print(list(itertools.permutations(l)))
[('A', 'B', 'C', 'AB'), ('A', 'B', 'AB', 'C'), ('A', 'C', 'B', 'AB'), ('A', 'C', 'AB', 'B'), ('A', 'AB', 'B', 'C'), ('A', 'AB', 'C', 'B'), ('B', 'A', 'C', 'AB'), ('B', 'A', 'AB', 'C'), ('B', 'C', 'A', 'AB'), ('B', 'C', 'AB', 'A'), ('B', 'AB', 'A', 'C'), ('B', 'AB', 'C', 'A'), ('C', 'A', 'B', 'AB'), ('C', 'A', 'AB', 'B'), ('C', 'B', 'A', 'AB'), ('C', 'B', 'AB', 'A'), ('C', 'AB', 'A', 'B'), ('C', 'AB', 'B', 'A'), ('AB', 'A', 'B', 'C'), ('AB', 'A', 'C', 'B'), ('AB', 'B', 'A', 'C'), ('AB', 'B', 'C', 'A'), ('AB', 'C', 'A', 'B'), ('AB', 'C', 'B', 'A')]
I need a way to find all combinations from two different lists where each element may or may not be null. For example with the two lists I'd like to call a function that returns a list of all these combinations:
a = ['A', 'S', 'B']
b = ['A', 'B']
find_combinations(a, b)
Should return:
[['A', 'S', 'B'], ['A', 'S'], ['S', 'B'], ['S']]
I can do this trivial example but if the list is more complicated say ['A', 'B', 'S', 'A', 'A'] then the possible options are much more complicated:
[['A', 'B', 'S', 'A', 'A'],
['A', 'B', 'S', 'A'],
['A', 'B', 'S', 'A'],
['B', 'S', 'A', 'A']
... etc.
I will assume the elements of b are hashable. In that case you can use the following code:
def without(a,i,bi,l):
if i >= len(a):
yield tuple(l)
else:
l.append(a[i])
for result in without(a,i+1,bi,l):
yield result
l.pop()
if a[i] in bi:
for result in without(a,i+1,bi,l):
yield result
def find_combinations(a, b):
for result in without(a,0,set(b),[]):
yield result
Here we first convert the b into a set to boost performance. This is strictly speaking not necessary. Then we use a recursive algorithm where for each element a[i] in a that is in b, we have a decision point whether to or not to include it in the result (that's why we perform the recursion again when that element is popped). When we reach the end of the list, we convert our running list l into a tuple(..). You can also use list(..) to convert it into a list.
We use a running list to boost performance a bit since concatenating two lists is done in O(n) whereas the running list can append(..) and pop(..) in O(1) amortized cost.
This will produce a generator of tuples. You can materialize the outcome of each generator with list(..) like:
>>> list(find_combinations(['A','S','B'],['A','B']))
[('A', 'S', 'B'), ('A', 'S'), ('S', 'B'), ('S',)]
>>> list(find_combinations(['A', 'B', 'S', 'A', 'A'],['A','B']))
[('A', 'B', 'S', 'A', 'A'), ('A', 'B', 'S', 'A'), ('A', 'B', 'S', 'A'), ('A', 'B', 'S'), ('A', 'S', 'A', 'A'), ('A', 'S', 'A'), ('A', 'S', 'A'), ('A', 'S'), ('B', 'S', 'A', 'A'), ('B', 'S', 'A'), ('B', 'S', 'A'), ('B', 'S'), ('S', 'A', 'A'), ('S', 'A'), ('S', 'A'), ('S',)]
In case lists are required, you can use map(list,..) to convert them to lists, like:
>>> list(map(list,find_combinations(['A','S','B'],['A','B'])))
[['A', 'S', 'B'], ['A', 'S'], ['S', 'B'], ['S']]
>>> list(map(list,find_combinations(['A', 'B', 'S', 'A', 'A'],['A','B'])))
[['A', 'B', 'S', 'A', 'A'], ['A', 'B', 'S', 'A'], ['A', 'B', 'S', 'A'], ['A', 'B', 'S'], ['A', 'S', 'A', 'A'], ['A', 'S', 'A'], ['A', 'S', 'A'], ['A', 'S'], ['B', 'S', 'A', 'A'], ['B', 'S', 'A'], ['B', 'S', 'A'], ['B', 'S'], ['S', 'A', 'A'], ['S', 'A'], ['S', 'A'], ['S']]
After playing around I found an alternative way to Willem Van Onsem's answer. Not quite as clean but also works.
def empty_derivations(rule, empty_list):
returned = []
returned.append(rule)
for element in returned:
for num, char in enumerate(element):
temp = element[:]
if char in empty_list:
del temp[num]
returned.append(temp)
return_list = []
for element in returned:
if element not in return_list:
return_list.append(element)
return return_list
When called gives:
>>> a = empty_derivations(['A', 'B', 'S', 'A', 'A'], ['A', 'B'])
>>> print(a)
[['A', 'B', 'S', 'A', 'A'],
['B', 'S', 'A', 'A'],
['A', 'S', 'A', 'A'],
['A', 'B', 'S', 'A'],
['S', 'A', 'A'],
['B', 'S', 'A'],
['A', 'S', 'A'],
['A', 'B', 'S'],
['S', 'A'],
['B', 'S'],
['A', 'S'],
['S']]