All combinations of list wIthout itertools - python

I'm trying to make a recursive function that finds all the combinations of a python list.
I want to input ['a','b','c'] in my function and as the function runs I want the trace to look like this:
['a','b','c']
['['a','a'],['b','a'],['c','a']]
['['a','a','b'],['b','a','b'],['c','a','b']]
['['a','a','b','c'],['b','a','b','c'],['c','a','b','c']]
My recursive function looks like this:
def combo(lst,new_lst = []):
for item in lst:
new_lst.append([lst[0],item])
print([lst[0],item])
return combo(new_lst,lst[1:])

The right answer is that you should use itertools.combinations. But if for some reason you don't want to, and want to write a recursive function, you can use the following piece of code. It is an adaptation of the erlang way of generating combinations, so it may seem a bit weird at first:
def combinations(N, iterable):
if not N:
return [[]]
if not iterable:
return []
head = [iterable[0]]
tail = iterable[1:]
new_comb = [ head + list_ for list_ in combinations(N - 1, tail) ]
return new_comb + combinations(N, tail)
This a very elegant way of thinking of combinations of size N: you take the first element of an iterable (head) and combine it with smaller (N-1) combinations of the rest of the iterable (tail). Then you add same size (N) combinations of the tail to that. That's how you get all possible combinations.
If you need all combinations, of all lengths you would do:
for n in range(1, len(iterable) + 1):
print(combinations(n, iterable))

Seems that you want all the product of a list, you can use itertools.product within the following function to return a list of generators:
>>> from itertools import product
>>> def pro(li):
... return [product(l,repeat=i) for i in range(2,len(l)+1)]
...
>>> for i in pro(l):
... print list(i)
...
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('c', 'c')]
[('a', 'a', 'a'), ('a', 'a', 'b'), ('a', 'a', 'c'), ('a', 'b', 'a'), ('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'a'), ('a', 'c', 'b'), ('a', 'c', 'c'), ('b', 'a', 'a'), ('b', 'a', 'b'), ('b', 'a', 'c'), ('b', 'b', 'a'), ('b', 'b', 'b'), ('b', 'b', 'c'), ('b', 'c', 'a'), ('b', 'c', 'b'), ('b', 'c', 'c'), ('c', 'a', 'a'), ('c', 'a', 'b'), ('c', 'a', 'c'), ('c', 'b', 'a'), ('c', 'b', 'b'), ('c', 'b', 'c'), ('c', 'c', 'a'), ('c', 'c', 'b'), ('c', 'c', 'c')]

Related

Using itertools product but needing combination behavior

I am trying to generate a list of possible strings of characters from input, accounting for wildcards "?" and "*". The ordering of list items should not matter, meaning if ABC already exists in the list, then I do not want to add ACB, or any other ordering (processing speed issue). The code I am using is below:
import itertools
from itertools import permutations
#####################################################
def getWordsFromTiles(tiles, word):
#####################################################
return all(word.count(i) <= tiles.count(i) for i in word)
#####################################################
Main
#####################################################
chars = A?*
wilds = [
('A','B','C','D','E','F','G','H','I','J','K',
'L','M','N','O','P','Q','R','S','T','U','V',
'W','X','Y','Z')
if char == "?" or char == "*" else (char) for char in chars]
for p in itertools.product(*wilds):
x = ''.join(p)
hits.extend([word for word in data if getWordsFromTiles(x.upper(), word) and word not in hits])
This generates a list like the following:
A,A,A
A,A,B
A,A,C
.....
A,B,A
I actually do not care about the order of these list, so I would like to not have A,B,A when I have already generated "A,A,B. Any ideas how to implement this?
actually do not care about the order of these list, so I would like to not have A,B,A when I have already generated "A,A,B".
Is this what you are looking for?
from itertools import combinations_with_replacement
s = ['A','B','C','D']
list(combinations_with_replacement(s,3))
[('A', 'A', 'A'),
('A', 'A', 'B'),
('A', 'A', 'C'),
('A', 'A', 'D'),
('A', 'B', 'B'),
('A', 'B', 'C'),
('A', 'B', 'D'),
('A', 'C', 'C'),
('A', 'C', 'D'),
('A', 'D', 'D'),
('B', 'B', 'B'),
('B', 'B', 'C'),
('B', 'B', 'D'),
('B', 'C', 'C'),
('B', 'C', 'D'),
('B', 'D', 'D'),
('C', 'C', 'C'),
('C', 'C', 'D'),
('C', 'D', 'D'),
('D', 'D', 'D')]

n-fold Cartesian product on a single list in Python [duplicate]

This question already has answers here:
Generating permutations with repetitions
(6 answers)
Closed 8 months ago.
How to compute the n-fold Cartesian product on a list, that is, A × ... × A (n times), in an elegant (concise) way in Python?
Examples:
>>> l = ["a", "b", "c"]
>>> cart_prod(l, 0)
[]
>>> cart_prod(l, 1)
[('a',), ('b',), ('c',)]
>>> cart_prod(l, 2)
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('c', 'c')]
>>> cart_prod(l, 3)
[('a', 'a', 'a'), ('a', 'a', 'b'), ('a', 'a', 'c'), ('a', 'b', 'a'), ('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'c', 'a'), ('a', 'c', 'b'), ('a', 'c', 'c'),
('b', 'a', 'a'), ('b', 'a', 'b'), ('b', 'a', 'c'), ('b', 'b', 'a'), ('b', 'b', 'b'), ('b', 'b', 'c'), ('b', 'c', 'a'), ('b', 'c', 'b'), ('b', 'c', 'c'),
('c', 'a', 'a'), ('c', 'a', 'b'), ('c', 'a', 'c'), ('c', 'b', 'a'), ('c', 'b', 'b'), ('c', 'b', 'c'), ('c', 'c', 'a'), ('c', 'c', 'b'), ('c', 'c', 'c')]
I came up with the following iterative solution:
def cart_prod(l, n):
if n == 0:
return [] # compute the result for n = 0
# preliminarily, create a list of lists instead of a list of tuples
res = [[x] for x in l] # initialize list with singleton tuples (n = 1)
for i in range(n-1):
res = [r + [x] for r in res for x in l] # concatenate each n-1 tuple with each element from a
res = [tuple(el) for el in res] # turn the list of lists into a list of tuples
return res
This code does the job, but is there a shorter, possibly one-liner definition, maybe a nested list comprehension or a lambda expression? I am interested in more compact solutions, not necessarily more readable ones.
This question is not a duplicate of Get the cartesian product of a series of lists?. I do not want the Cartesian product of a series of lists crossed with each other. I want the Cartesian product of a single list crossed n-times with itself, where n is a parameter given to the function.
itertools.product takes a keyword argument to indicate the given arguments should be repeated.
>>> from itertools import product
>>> list(product([1,2], repeat=0))
[()]
>>> list(product([1,2], repeat=1))
[(1,), (2,)]
>>> list(product([1,2], repeat=2))
[(1, 1), (1, 2), (2, 1), (2, 2)]
This works with multiple iterables as well.
# Equivalent to list(product([1,2], ['a', 'b'], [1,2], ['a', 'b']))
>>> list(product([1,2], ['a', 'b'], repeat=2))
[(1, 'a', 1, 'a'), (1, 'a', 1, 'b'), (1, 'a', 2, 'a'), (1, 'a', 2, 'b'), (1, 'b', 1, 'a'), (1, 'b', 1, 'b'), (1, 'b', 2, 'a'), (1, 'b', 2, 'b'), (2, 'a', 1, 'a'), (2, 'a', 1, 'b'), (2, 'a', 2, 'a'), (2, 'a', 2, 'b'), (2, 'b', 1, 'a'), (2, 'b', 1, 'b'), (2, 'b', 2, 'a'), (2, 'b', 2, 'b')]

Create a dictionary with length of elements in a list as keys

I have a list where there are multiple elements as tuples stored in a list, I want to create a dictionary where the key is length like 1,2 etc and the elements of respective lengths.
The example of list is
combination = [('A',), ('B',), ('C',), ('D',), ('A', 'B'), ('A','C'),
('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D'), ('A', 'B', 'C'),
('A', 'B', 'D'), ('A', 'C', 'D'), ('B', 'C', 'D'),('A', 'B', 'C', 'D')]
I have tried
temp_dict = {len(i): i for i in combinations}
The desired output is
{1: [('A',), ('B',), ('C',), ('D',)], 2: [('A', 'B'), ('A','C'),
('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')], 3: [('A', 'B', 'C'),
('A', 'B', 'D'), ('A', 'C', 'D'), ('B', 'C', 'D')], 4: [('A', 'B', 'C', 'D')]}```
You can try a dictionary comprehension with a list comprehension within it
temp_dict = {len(i): [x for x in combination if len(x) == len(i)] for i in combination}
print(temp_dict)
Or you could use a setdefault:
temp_dict = {}
for i in combination:
temp_dict.setdefault(len(i), []).append(i)
print(temp_dict)
Both Output:
{1: [('A',), ('B',), ('C',), ('D',)], 2: [('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')], 3: [('A', 'B', 'C'), ('A', 'B', 'D'), ('A', 'C', 'D'), ('B', 'C', 'D')], 4: [('A', 'B', 'C', 'D')]}
Your current approach {len(i): i for i in combination} actually picks the last tuple of a specific length and adds it to the dictionary, which is not what you want, instead you want a list of all such tuples.
You can use collections.defaultdict to create a dict of lists as values. Then you can iterate over the list and append the tuples of the same length to the key
from collections import defaultdict
res = defaultdict(list)
#Iterate over the list
for item in combination:
#Append tuples with same length to same value list
res[len(item)].append(item)
print(dict(res))
The output will be
{1: [('A',), ('B',), ('C',), ('D',)],
2: [('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')],
3: [('A', 'B', 'C'), ('A', 'B', 'D'), ('A', 'C', 'D'), ('B', 'C', 'D')],
4: [('A', 'B', 'C', 'D')]}
Another approach is to use itertools.groupby. Note that groupby assumes your data is sorted.
from itertools import groupby
{k: list(g) for k, g in groupby(combination, key=len)}
Output:
{1: [('A',), ('B',), ('C',), ('D',)],
2: [('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')],
3: [('A', 'B', 'C'), ('A', 'B', 'D'), ('A', 'C', 'D'), ('B', 'C', 'D')],
4: [('A', 'B', 'C', 'D')]}
Another shot at it is via itertools.groupby:
>>> from itertools import groupby
>>> dict([(cnt, list(l)) for cnt, l in groupby(combinations, len)])
{1: [('A',), ('B',), ('C',), ('D',)], 2: [('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')], 3: [('A', 'B', 'C'), ('A', 'B', 'D'), ('A', 'C', 'D'), ('B', 'C', 'D')], 4: [('A', 'B', 'C', 'D')]}

Python fastest method to group pairs from a list of items

As a part of my project, I need to group characters as pairs (unique). I have more than 1000 of these characters in a list. What would be the fastest and optimized method to create unique pairs out of these list of characters. I am using itertools currently and my code seems to perform pretty badly.
My Code using itertools:
import itertools
characters = ['A', 'B', 'C', 'D', 'E']
relations = []
for character in range(len(characters) + 1):
for combination in itertools.combinations(characters, character):
if len(combination) == 2:
relations.append(combination)
print relations
Expected Output:
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('B', 'C'),
('B', 'D'), ('B', 'E'), ('C', 'D'), ('C', 'E'), ('D', 'E')]
All you need are combinations of length 2?
In [48]: characters = ['A', 'B', 'C', 'D', 'E']
In [50]: list(itertools.combinations(characters, 2))
Out[50]:
[('A', 'B'),
('A', 'C'),
('A', 'D'),
('A', 'E'),
('B', 'C'),
('B', 'D'),
('B', 'E'),
('C', 'D'),
('C', 'E'),
('D', 'E')]
You are also generating combinations of length 3 to len(characters) and throwing them all away.
characters = ['A', 'B', 'C', 'D', 'E']
relations = list(itertools.combinations(characters, 2))

From a combination, get subsets with members containing the same first element, python

Suppose I have the following list:
ls = ['a', 'b', 'c', 'd']
I get a combination using
list(itertools.combinations(iterable, 2))
>>> [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
What I'd like to do is break this combination into subsets, such that the first member of each tuple in the subset is the same:
subset1: [('a', 'b'), ('a', 'c'), ('a', 'd')]
subset2: [('b', 'c'), ('b', 'd'),
subset3: [('c', 'd')]
Any ideas?
>>> import itertools as it
>>> ls = ['a', 'b', 'c', 'd']
>>> ii=it.groupby( it.combinations(ls, 2), lambda x: x[0] )
>>> for key, iterator in ii:
... print key, list(iterator)
...
a [('a', 'b'), ('a', 'c'), ('a', 'd')]
b [('b', 'c'), ('b', 'd')]
c [('c', 'd')]
If you don't like lambda, you could use operator.itemgetter(0) instead of lambda x: x[0].
subset = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
subsets = [[x for x in subset where x[0] == y] for y in ['a','b','c']]
try this:
[filter(lambda k:k[0]==p,comb) for p in ls]
where:
ls = ['a', 'b', 'c', 'd']
comb = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
the output is:
[[('a', 'b'), ('a', 'c'), ('a', 'd')], [('b', 'c'), ('b', 'd')], [('c', 'd')], []]

Categories

Resources