Reputation: 63
Hey guys I'm using python and I was just wondering how we can make combinations of lists of specific lengths from an original list of elements? For example, I have an original list ["2H", "AH", "KH", "QH", "JH", "0H", "9H"]
, is there any way for me to create a final list where ALL of the new assorted lists of specific lengths (3
to 5
) are contained?
Basically from the original list above, I want a returned list as shown below:
[['9H', '0H', 'JH'], ['0H', 'JH', 'QH'], ['JH', 'QH', 'KH'], ['QH', 'KH', 'AH'],
['KH', 'AH', '2H'], ['9H', '0H', 'JH', 'QH'], ['0H', 'JH', 'QH', 'KH'],
['JH', 'QH', 'KH', 'AH'], ['QH', 'KH', 'AH', '2H'], ['9H', '0H', 'JH', 'QH', 'KH'],
['0H', 'JH', 'QH', 'KH', 'AH'], ['JH', 'QH', 'KH', 'AH', '2H']]
Thanks!
Upvotes: 1
Views: 83
Reputation: 133614
>>> from itertools import islice, chain
>>> L = ["2H", "AH", "KH", "QH", "JH", "0H", "9H"]
>>> list(chain.from_iterable(
zip(*[islice(reversed(L),i,None) for i in range(j)])
for j in range(3,6)))
[('9H', '0H', 'JH'), ('0H', 'JH', 'QH'), ('JH', 'QH', 'KH'), ('QH', 'KH', 'AH'),
('KH', 'AH', '2H'), ('9H', '0H', 'JH', 'QH'), ('0H', 'JH', 'QH', 'KH'),
('JH', 'QH', 'KH', 'AH'), ('QH', 'KH', 'AH', '2H'), ('9H', '0H', 'JH', 'QH', 'KH'),
('0H', 'JH', 'QH', 'KH', 'AH'), ('JH', 'QH', 'KH', 'AH', '2H')]
Explanation
This solution builds on the use of zip
.
>>> zip(L,L)
[('2H', '2H'), ('AH', 'AH'), ('KH', 'KH'), ('QH', 'QH'), ('JH', 'JH'), ('0H', '0H'), ('9H', '9H')]
This shows an example of how zip
works, by taking an item from each of its paramters together.
>>> zip(L,L[1:])
[('2H', 'AH'), ('AH', 'KH'), ('KH', 'QH'), ('QH', 'JH'), ('JH', '0H'), ('0H', '9H')]
By starting at the 1st item of the same list as the second paramater you can get every 2 items.
>>> zip(L,L[1:],L[2:])
[('2H', 'AH', 'KH'), ('AH', 'KH', 'QH'), ('KH', 'QH', 'JH'), ('QH', 'JH', '0H'), ('JH', '0H', '9H')]
Same for every 3 items.
>>> zip(*[L[i:] for i in range(3)])
[('2H', 'AH', 'KH'), ('AH', 'KH', 'QH'), ('KH', 'QH', 'JH'), ('QH', 'JH', '0H'), ('JH', '0H', '9H')]
To do this automatically you can use the *
(splat) to get the arguments of zip
from a list comprehension.
In the example, the results come in reverse, so reversed
gives a reverse iterator through the list. To slice an iterator, islice
from itertools must be used. islice
takes the iterable followed by the index to start the slice and the index to end it. None
can be used to go all the way to the end of the iterable.
>>> zip(*[islice(reversed(L),i,None) for i in range(3)])
[('9H', '0H', 'JH'), ('0H', 'JH', 'QH'), ('JH', 'QH', 'KH'), ('QH', 'KH', 'AH'), ('KH', 'AH', '2H')]
So that gives all the results for every 3 items. Now every 4 and 5 items are needed so this operation is performed for range(3)
, range(4)
and range(5)
.
(zip(*[islice(reversed(L),i,None) for i in range(j)]) for j in range(3,6))
This would give a generator with a list for each of 3
, 4
, and 5
but they need to be all one list. They can be chained together withchain.from_iterable
with the result being converted to a list
.
Upvotes: 3
Reputation: 10163
Use itertools
import itertools
original = ["2H", "AH", "KH", "QH", "JH", "0H", "9H"]
result = itertools.chain()
for size in range(3, 6):
curr_subsets = itertools.combinations(original, size)
result = itertools.chain(result, curr_subsets)
result_as_list = list(result)
Upvotes: -1