I have a list containing ['a', 'bill', 'smith'] and I would like to write a python code in order to obtain all possible combinations applying a certain criteria. To be more precise, I would like to obtain combination of those three element in the list plus the first letter of each element if that element isn't yet present in the output list. For example, given the list ['a', 'bill', 'smith'], one part of the expected output would be: ['a', 'bill', 'smith'], ['bill', 'smith'], ['a', 'smith'] but as well, ['a', 'b, 'smith'], ['bill, 's'], ['a', 's']. What I'm not expected to obtain is output like this ['s', 'bill, 'smith'] as the first element (s) is already taken into account by the third element ('smith'). Can someone help me?
This is what I've done so far:
mapping = dict(enumerate(['a', 'bill', 'smith']))
for i in mapping.items():
if len(i[1])>1:
mapping[i[0]] = [i[1], i[1][0]]
else:
mapping[i[0]] = [i[1]]
print(mapping)
{0: ['a'], 1: ['bill', 'b'], 2: ['william', 'w'], 3: ['stein', 's']}
I'm now stucked. I would like to use itertools library to iterate over the dict values to create all possible combinations.
Thanks in advance :)
You can use some itertools:
from itertools import product, permutations
lst = [list({s, s[:1]}) for s in ['a', 'bill', 'smith']]
# [['a'], ['bill', 'b'], ['s', 'smith']]
for perms in map(permutations, product(*lst)):
for p in perms:
print(p)
('a', 'bill', 's')
('a', 's', 'bill')
('bill', 'a', 's')
('bill', 's', 'a')
('s', 'a', 'bill')
('s', 'bill', 'a')
('a', 'bill', 'smith')
('a', 'smith', 'bill')
('bill', 'a', 'smith')
('bill', 'smith', 'a')
('smith', 'a', 'bill')
('smith', 'bill', 'a')
('a', 'b', 's')
('a', 's', 'b')
('b', 'a', 's')
('b', 's', 'a')
('s', 'a', 'b')
('s', 'b', 'a')
('a', 'b', 'smith')
('a', 'smith', 'b')
('b', 'a', 'smith')
('b', 'smith', 'a')
('smith', 'a', 'b')
('smith', 'b', 'a')
The first step creates the list of equivalent lists:
[['a'], ['bill', 'b'], ['s', 'smith']]
then, product produces the cartesian product of the lists in said lists:
('a', 'bill', 's')
('a', 'bill', 'smith')
('a', 'b', 's')
...
and for each of those, permutations gives you, well, all permutations:
('a', 'bill', 's')
('a', 's', 'bill')
('bill', 'a', 's')
...
You could do something like this with combinations from itertools:
Here I am assuming you want the first letter of each word in the list only if it has a length greater than 1. If not you can change the if condition.
from itertools import combinations
lst = ['a', 'bill', 'smith']
lst_n=[]
for words in lst:
lst_n.append(words)
if len(words)>1:
lst_n.append(words[0])
for t in range(1,len(lst_n)+1):
for comb in combinations(lst_n,r=t):
print(list(comb))
OUTPUT:
['a']
['bill']
['b']
['smith']
['s']
['a', 'bill']
['a', 'b']
['a', 'smith']
['a', 's']
['bill', 'b']
['bill', 'smith']
['bill', 's']
['b', 'smith']
['b', 's']
['smith', 's']
['a', 'bill', 'b']
['a', 'bill', 'smith']
['a', 'bill', 's']
['a', 'b', 'smith']
['a', 'b', 's']
['a', 'smith', 's']
['bill', 'b', 'smith']
['bill', 'b', 's']
['bill', 'smith', 's']
['b', 'smith', 's']
['a', 'bill', 'b', 'smith']
['a', 'bill', 'b', 's']
['a', 'bill', 'smith', 's']
['a', 'b', 'smith', 's']
['bill', 'b', 'smith', 's']
['a', 'bill', 'b', 'smith', 's']
Here if you want combinations to be of length 3 only remove the for loop with range and set r=3.
Related
Suppose l = ['a', 'b', 'c', 'd'] ...
I need to generate the following combinations/permutations from this list (in general, the list could have. more elements):
['a', 'b', 'c', 'd']
['a', 'b', 'd', 'c']
['a', 'c', 'b', 'd']
['a', 'c', 'd', 'b']
['a', 'd', 'b', 'c']
['a', 'd', 'c', 'b']
['b', 'c', 'a', 'd']
['b', 'c', 'd', 'a']
['b', 'd', 'a', 'c']
['b', 'd', 'c', 'a']
['c', 'd', 'a', 'b']
['c', 'd', 'b', 'a']
So, for the first two positions in the list order does not matter, although I need to take all combinations of list elements, while in the last two (or n) positions of the list order does matter. I've tried various combinations of using permutations and combinations from itertools, all with no success (I dare not post my code for fear of embarrassment).
The most direct solution using the existing itertools library functions is to select the first two elements as a combination, and then the rest as a permutation of the remaining elements:
import itertools
def partly_unordered_permutations(lst, k):
elems = set(lst)
for c in itertools.combinations(lst, k):
for d in itertools.permutations(elems - set(c)):
yield c + d
Usage:
>>> for p in partly_unordered_permutations('abcd', 2):
... print(p)
...
('a', 'b', 'c', 'd')
('a', 'b', 'd', 'c')
('a', 'c', 'b', 'd')
('a', 'c', 'd', 'b')
('a', 'd', 'b', 'c')
('a', 'd', 'c', 'b')
('b', 'c', 'a', 'd')
('b', 'c', 'd', 'a')
('b', 'd', 'a', 'c')
('b', 'd', 'c', 'a')
('c', 'd', 'a', 'b')
('c', 'd', 'b', 'a')
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']]
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']
I have two lists. Both lists will have the same sets of rows. I would like to add list2 columns to list1 to create one list.
list1 = [('gi1','1','2'),
('gi1','1','2'),
('gi1','1','2')]
list2 = [('a','b','c','d','e','f','g'),
('a','b','c','d','e','f','g'),
('a','b','c','d','e','f','g')]
I would like to merge these into a list that looks like this:
[('gi1','1','2','a','b','c','d','e','f','g'),
('gi1','1','2','a','b','c','d','e','f','g'),
('gi1','1','2','a','b','c','d','e','f','g')]
I would use the help of itertools.chain
>>> list1=[('gi1','1','2'),
('gi1','1','2'),
('gi1','1','2')]
>>> list2=[('a','b','c','d','e','f','g'),
('a','b','c','d','e','f','g'),
('a','b','c','d','e','f','g')]
>>> from itertools import chain
>>> [tuple(chain(x, y)) for x, y in zip(list1, list2)]
[('gi1', '1', '2', 'a', 'b', 'c', 'd', 'e', 'f', 'g'), ('gi1', '1', '2', 'a', 'b', 'c', 'd', 'e', 'f', 'g'), ('gi1', '1', '2', 'a', 'b', 'c', 'd', 'e', 'f', 'g')]
If you know that both lists have the same length:
[list1[i] + list2[i] for i in range(len(list1))]
Another way to do it. Use Zip()
>>> [e1+e2 for e1,e2 in zip(list1,list2)]
[('gi1', '1', '2', 'a', 'b', 'c', 'd', 'e', 'f', 'g'), ('gi1', '1', '2', 'a', 'b', 'c', 'd', 'e', 'f', 'g'), ('gi1', '1', '2', 'a', 'b', 'c', 'd', 'e', 'f', 'g')]