Adhy Karina
Adhy Karina

Reputation: 63

Assorting elements in a list into a list of lists of specific lengths

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

Answers (2)

jamylak
jamylak

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

bossylobster
bossylobster

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

Related Questions