I have a list like this:
l = [['a', 'b', 'c'], ['a', 'b'], ['g', 'h', 'r', 'w']]
I want to pick an element from each list and combine them to be a string.
For example: 'aag', 'aah', 'aar', 'aaw', 'abg', 'abh' ....
However, the length of the list l and the length of each inner list are all unknown before the program is running. So how can I do want I want?
Take a previous solution and use itertools.product(*l) instead.
If anybody's interested in the algorithm, here's a very simple way to use recursion to find the combos:
l = [['a', 'b', 'c'], ['a', 'b'], ['g', 'h', 'r', 'w']]
def permu(lists, prefix=''):
if not lists:
print prefix
return
first = lists[0]
rest = lists[1:]
for letter in first:
permu(rest, prefix + letter)
permu(l)
using recursion
def permutenew(l):
if len(l)==1:
return l[0]
else:
lnew=[]
for a in l[0]:
for b in permutenew(l[1:]):
lnew.append(a+b)
return lnew
l = [['a', 'b', 'c'], ['a', 'b'], ['g', 'h', 'r', 'w']]
print permutenew(l)
Piggy-backing off of JasonWoof's answer. The following will create a list instead of printing. Be mindful that this may be very slow as it requires a lot of memory to store the values.
from __future__ import print_function
import itertools # Not actually used in the code below
def permu(lists):
def fn(lists, group=[], result=[]):
if not lists:
result.append(group)
return
first, rest = lists[0], lists[1:]
for letter in first:
fn(rest, group + [letter], result)
result = []
fn(lists, result=result)
return result
if __name__ == '__main__':
ll = [ [[1, 2, 3], [5, 10], [42]],
[['a', 'b', 'c'], ['a', 'b'], ['g', 'h', 'r', 'w']] ]
nth = lambda i: 'Permutation #{0}:\n{1}'.format(i, '-'*16)
# Note: permu(list) can be replaced with itertools.product(*l)
[[print(p) for p in [nth(i)]+permu(l)+['\n']] for i,l in enumerate(ll)]
Result
Permutation #0:
----------------
[1, 5, 42]
[1, 10, 42]
[2, 5, 42]
[2, 10, 42]
[3, 5, 42]
[3, 10, 42]
Permutation #1:
----------------
['a', 'a', 'g']
['a', 'a', 'h']
['a', 'a', 'r']
['a', 'a', 'w']
['a', 'b', 'g']
['a', 'b', 'h']
['a', 'b', 'r']
['a', 'b', 'w']
['b', 'a', 'g']
['b', 'a', 'h']
['b', 'a', 'r']
['b', 'a', 'w']
['b', 'b', 'g']
['b', 'b', 'h']
['b', 'b', 'r']
['b', 'b', 'w']
['c', 'a', 'g']
['c', 'a', 'h']
['c', 'a', 'r']
['c', 'a', 'w']
['c', 'b', 'g']
['c', 'b', 'h']
['c', 'b', 'r']
['c', 'b', 'w']
Below is an equivalent substitution for itertools.product(*iterables[, repeat]):
This function is equivalent to the following code, except that the actual implementation does not build up intermediate results in memory:
def product(*args, **kwds):
pools = list(map(tuple, args)) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
Quite easy with itertools.product :
>>> import itertools
>>> list(itertools.product("abc", "ab", "ghrw"))
[('a', 'a', 'g'), ('a', 'a', 'h'), ('a', 'a', 'r'), ('a', 'a', 'w'), ('a', 'b', 'g'), ('a', 'b', 'h'), ('a', 'b', 'r'), ('a', 'b', 'w'), ('b', 'a', 'g'), ('b', 'a', 'h'), ('b', 'a', 'r'), ('b', 'a', 'w'), ('b', 'b', 'g'), ('b', 'b', 'h'), ('b', 'b', 'r'), ('b', 'b', 'w'), ('c', 'a', 'g'), ('c', 'a', 'h'), ('c', 'a', 'r'), ('c', 'a', 'w'), ('c', 'b', 'g'), ('c', 'b', 'h'), ('c', 'b', 'r'), ('c', 'b', 'w')]
Here you go
reduce(lambda a,b: [i+j for i in a for j in b], l)
OUT: ['aag', 'aah', 'aar', 'aaw', 'abg', 'abh', 'abr', 'abw', 'bag', 'bah', 'bar', 'baw', 'bbg', 'bbh', 'bbr', 'bbw', 'cag', 'cah', 'car', 'caw', 'cbg', 'cbh', 'cbr', 'cbw']
If you'd like to reuse/regeneralize:
def opOnCombos(a,b, op=operator.add):
return [op(i,j) for i in a for j in b]
def f(x):
return lambda a,b: opOnCombo(a,b,x)
reduce(opOnCombos, l) //same as before
reduce(f(operator.mul), l)) //multiply combos of several integer list
Related
I'm not really sure how to frame my question, but here's a try. I have a list of strings and tuples of strings. I want all combinations such that I pick only one value from each tuple.
It's much easier to demonstrate with an example.
Input:
x = ['a', ('b', 'c'), ('d', 'e'), 'f']
Output:
y = [
['a', 'b', 'd', 'f'],
['a', 'c', 'd', 'f'],
['a', 'b', 'e', 'f'],
['a', 'c', 'e', 'f']
]
Example 2:
Input:
x = ['a', ('b', 'c'), ('d', 'e'), 'f', ('g', 'h')]
Output:
y = [
['a', 'b', 'd', 'f', 'g'],
['a', 'c', 'd', 'f', 'g'],
['a', 'b', 'e', 'f', 'g'],
['a', 'c', 'e', 'f', 'g'],
['a', 'b', 'd', 'f', 'h'],
['a', 'c', 'd', 'f', 'h'],
['a', 'b', 'e', 'f', 'h'],
['a', 'c', 'e', 'f', 'h']
]
x = ['a', ('b', 'c'), ('d', 'e'), 'f', ('g', 'h')]
First normalize your input
x = [tuple(xx) for xx in x if not isinstance(x, tuple)]
Then:
import iterools
list(itertools.product(*x))
In the output your have a list of tuples, it should be very easy to get list of list as you want.
Actually the normalization step is not necessary.
I'm trying to extract all the unique combinations of strings from a list of lists in Python. For example, in the code below, ['a', 'b','c'] and ['b', 'a', 'c'] are not unique, while ['a', 'b','c'] and ['a', 'e','f'] or ['a', 'b','c'] and ['d', 'e','f'] are unique.
I've tried converting my list of lists to a list of tuples and using sets to compare elements, but all elements are still being returned.
combos = [['a', 'b', 'c'], ['c', 'b', 'a'], ['d', 'e', 'f'], ['c', 'a', 'b'], ['c', 'f', 'b']]
# converting list of list to list of tuples, so they can be converted into a set
combos = [tuple(item) for item in combos]
combos = set(combos)
grouping_list = set()
for combination in combos:
if combination not in grouping_list:
grouping_list.add(combination)
##
print grouping_list
>>> set([('a', 'b', 'c'), ('c', 'a', 'b'), ('d', 'e', 'f'), ('c', 'b', 'a'), ('c', 'f', 'b')])
How about sorting, (and using a Counter)?
from collections import Counter
combos = [['a', 'b', 'c'], ['c', 'b', 'a'], ['d', 'e', 'f'], ['c', 'a', 'b'], ['c', 'f', 'b']]
combos = Counter(tuple(sorted(item)) for item in combos)
print(combos)
returns:
Counter({('a', 'b', 'c'): 3, ('d', 'e', 'f'): 1, ('b', 'c', 'f'): 1})
EDIT: I'm not sure if I'm correctly understanding your question. You can use a Counter to count occurances, or use a set if you're only interested in the resulting sets of items, and not in their uniqueness.
Something like:
combos = set(tuple(sorted(item)) for item in combos)
Simply returns
set([('a', 'b', 'c'), ('d', 'e', 'f'), ('b', 'c', 'f')])
>>> set(tuple(set(combo)) for combo in combos)
{('a', 'c', 'b'), ('c', 'b', 'f'), ('e', 'd', 'f')}
Simple but if we have same elements in the combo, it will return wrong answer. Then, sorting is the way to go as suggested in others.
How about this:
combos = [['a', 'b', 'c'], ['c', 'b', 'a'], ['d', 'e', 'f'], ['c', 'a', 'b'], ['c', 'f', 'b']]
print [list(y) for y in set([''.join(sorted(c)) for c in combos])]
I'm having so much trouble understanding my issue:
I got 2 lists:
from = ['A', 'B', 'C']
to = ['D', 'E', 'F']
I need to produce a matrix that combines each item from one list to the other as such:
final = [[['A', 'D'], ['B', 'E'], ['C', 'F']],
[['A', 'D'], ['B', 'F'], ['C', 'E']],
[['A', 'E'], ['B', 'F'], ['C', 'D']],
[['A', 'E'], ['B', 'D'], ['C', 'F']],
[['A', 'F'], ['B', 'D'], ['C', 'E']],
[['A', 'F'], ['B', 'E'], ['C', 'D']]]
I was trying to do this with this:
for i in range(len(initial)):
for j in range(len(transformed)):
self.semantic_networks[j][i][0] = self.initial_figure[i]['name']
self.semantic_networks[i][j][1] = self.transformed_figure[(j + i) % len(self.transformed_figure)]['name']
But, I'm getting only the top:
[['A', 'D'], ['B', 'E'], ['C', 'F']]
[['A', 'E'], ['B', 'F'], ['C', 'D']]
[['A', 'F'], ['B', 'D'], ['C', 'E']]
[[0, 0], [0, 0], [0, 0]]
[[0, 0], [0, 0], [0, 0]]
[[0, 0], [0, 0], [0, 0]]
What am I trying to get? Combination? Permutation? Combination of combinations??
Any hints???
Apply itertools.permutations on the second list and then zip each permutation with first list.
from itertools import permutations
lst1 = ['A', 'B', 'C']
lst2 = ['D', 'E', 'F']
for p in permutations(lst2):
print zip(lst1, p)
#
[('A', 'D'), ('B', 'E'), ('C', 'F')]
[('A', 'D'), ('B', 'F'), ('C', 'E')]
[('A', 'E'), ('B', 'D'), ('C', 'F')]
[('A', 'E'), ('B', 'F'), ('C', 'D')]
[('A', 'F'), ('B', 'D'), ('C', 'E')]
[('A', 'F'), ('B', 'E'), ('C', 'D')]
It seems you want the combination of all possible permutations:
import itertools
a = ['A', 'B', 'C']
b = ['D', 'E', 'F']
items = zip(itertools.permutations(a), itertools.permutations(b))
I have a 2d list of characters like
[['J', 'A', 'M', 'E', 'S'],
['F', 'C', 'A', 'A', 'A'],
['F', 'A', 'B', 'B', 'B']]
What is the best way to go about sorting the first list alphabetically, with the proceeding lists following, ie:
[['A', 'E', 'J', 'M', 'S'],
['C', 'A', 'F', 'A', 'A'],
['A', 'B', 'F', 'B', 'B']]
You can use zip():
>>> [list(t) for t in zip(*sorted(zip(*s)))]
[['A', 'E', 'J', 'M', 'S'], ['C', 'A', 'F', 'A', 'A'], ['A', 'B', 'F', 'B', 'B']]
where s is your list of lists.
The other answers demonstrate how it can be done in one line. This answer illustrates how this works:
Given a list, l:
In [1]: l = [['J', 'A', 'M', 'E', 'S'],
...: ['F', 'C', 'A', 'A', 'A'],
...: ['F', 'A', 'B', 'B', 'B']]
Group the columns into tuples, by passing each row into zip():
In [2]: zip(*l)
Out[2]:
[('J', 'F', 'F'),
('A', 'C', 'A'),
('M', 'A', 'B'),
('E', 'A', 'B'),
('S', 'A', 'B')]
Sort this list of tuples:
In [3]: sorted(zip(*l))
Out[3]:
[('A', 'C', 'A'),
('E', 'A', 'B'),
('J', 'F', 'F'),
('M', 'A', 'B'),
('S', 'A', 'B')]
Note that if the first list contains duplicate items then this sort is not a stable sort.
Transpose the list again to get three lists of tuples:
In [4]: zip(*sorted(zip(*l)))
Out[4]:
[('A', 'E', 'J', 'M', 'S'),
('C', 'A', 'F', 'A', 'A'),
('A', 'B', 'F', 'B', 'B')]
Convert the list of tuples back to a list of lists, using a list comprehension:
In [5]: [list(t) for t in zip(*sorted(zip(*l)))]
Out[5]:
[['A', 'E', 'J', 'M', 'S'],
['C', 'A', 'F', 'A', 'A'],
['A', 'B', 'F', 'B', 'B']]
>>> l = [['J', 'A', 'M', 'E', 'S'],
... ['F', 'C', 'A', 'A', 'A'],
... ['F', 'A', 'B', 'B', 'B']]
>>> zip(*sorted(zip(*l)))
[('A', 'E', 'J', 'M', 'S'), ('C', 'A', 'F', 'A', 'A'), ('A', 'B', 'F', 'B', 'B')]
if you need lists in result:
>>> map(list, zip(*sorted(zip(*l))))
[['A', 'E', 'J', 'M', 'S'], ['C', 'A', 'F', 'A', 'A'], ['A', 'B', 'F', 'B', 'B']]
Ok, so I've got information in the form of
(('A', 'B', 'C'), ('D', 'E', 'F'), ('H', 'I', 'J'))
and I would like to convert this to
[['A', 'B', 'C'], ['D', 'E', 'F'], ['H', 'I', 'J']]
What is the best/easiest way to do this?
List comprehension:
tpl = (('A', 'B', 'C'), ('D', 'E', 'F'), ('H', 'I', 'J'))
lst = [list(x) for x in tpl]
a = (('A', 'B', 'C'), ('D', 'E', 'F'), ('H', 'I', 'J'))
print map(list, a)
prints
[['A', 'B', 'C'], ['D', 'E', 'F'], ['H', 'I', 'J']]
>>> data = (('A', 'B', 'C'), ('D', 'E', 'F'), ('H', 'I', 'J'))
>>> [list(tup) for tup in data]
[['A', 'B', 'C'], ['D', 'E', 'F'], ['H', 'I', 'J']]
Here is a simple recursive solution for any number of nested tuples:
>>> tup = (('A', ('B', 'C')), ('D', 'E', 'F', ('H', 'I', 'J')))
>>> listify = lambda x: map(listify, x) if isinstance(x, tuple) else x
>>> listify(tup)
[['A', ['B', 'C']], ['D', 'E', 'F', ['H', 'I', 'J']]]
For Python 3 replace map(listify, x) with list(map(listify, x)).
If you know the structure is only two levels, try:
x = (('A', 'B', 'C'), ('D', 'E', 'F'), ('H', 'I', 'J'))
y = [ list(t) for t in x ]
If there might be deeper nesting, you'll want recursion -- see F.J's answer.