evelyn_7
evelyn_7

Reputation: 5

Itertools, combinations

I have a question. I use combinations to get different combinations from a list. However, if I wish to get a more specific combinations with ascending order(3D,4D,5D), but not (4D,5D,8D), how should I do?

for example:

from itertools import combinations

cards = ["3D", "4D", "5D", "6D"]
comb = []
for j in combinations(cards, 3):
    comb.append(list(j))
for j in combinations(cards, 4)):
    comb.append(list(j))

But I got an output like:

["3D", "4D", "5D"], ["3D", "4D", "6D"], ["3D", "5D", "6D"], ["4D", "5D", "6D"], ["3D", "4D", "5D", "6D"]

how can I get an output like this?

[["3D", "4D", "5D"], ["4D", "5D", "6D"], ["3D", "4D", "5D", "6D"]]

Upvotes: 0

Views: 2241

Answers (2)

Padraic Cunningham
Padraic Cunningham

Reputation: 180512

Step through the list and zip each 3 consecutive elements together. Then add the complete list of cards at the end.

print ([list(t) for t in zip(*(cards[i:] for i in xrange(3)))]+[cards])
[['3D', '4D', '5D'], ['4D', '5D', '6D'], ['3D', '4D', '5D', '6D']]

If you want to use it on longer lists and group 5 elements together you can change xrange to xrange(5):

cards = ["3D", "4D", "5D", "6D","7D","8D","9D"]
print ([list(t) for t in zip(*(cards[i:] for i in xrange(5)))]+[cards])
[['3D', '4D', '5D', '6D', '7D'], ['4D', '5D', '6D', '7D', '8D'], ['5D', '6D', '7D', '8D', '9D'], ['3D', '4D', '5D', '6D', '7D', '8D', '9D']]

If you card list is not in sorted order you can call the list method sort before you zip like:

cards = ["5D", "6D","3D", "4D"]    
cards.sort()
print [list(t) for t in zip(*(cards[i:] for i in xrange(3)))]+[cards]#
[['3D', '4D', '5D'], ['4D', '5D', '6D'], ['3D', '4D', '5D', '6D']]

Upvotes: 1

A.J. Uppal
A.J. Uppal

Reputation: 19274

Use the following code:

from itertools import combinations

def check(lst):
        for i in range(len(lst)):
            try:
                    if lst[i+1]-lst[i] != 1:
                            return False
            except IndexError:
                    pass
        return True

cards = ["3D", "4D", "5D", "6D"]
comb = []
for j in combinations(cards, 3):
    comb.append(list(j))
for j in combinations(cards, 4):
    comb.append(list(j))

subs = []
for i in comb:
        subs.append([int(item[0]) for item in i])

subs = [item for item in subs if check(item) == True]

comb = []

for i in subs:
        comb.append([str(item)+'D' for item in i])

print comb

This code converts each sublist to a list of ints using the following code:

>>> item = ['3D', '4D', '6D']
>>> [int(val[0]) for val in item]
[3, 4, 6]
>>> 

We then make sure these numbers are directly ascending:

>>> def check(lst):
...         for i in range(len(lst)):
...             try:
...                     if lst[i+1]-lst[i] != 1:
...                             return False
...             except IndexError:
...                     pass
...         return True
... 
>>> check([3, 4, 6])
False
>>> check([3, 4, 5])
True
>>> check([3, 4, 5, 6])
True
>>> check([3, 4, 5, 8])
False
>>> 

Then using the above logic, we filter everything out, giving the following.

Running:

bash-3.2$ python check.py
[['3D', '4D', '5D'], ['4D', '5D', '6D'], ['3D', '4D', '5D', '6D']]
bash-3.2$ 

Upvotes: 0

Related Questions