简体   繁体   中英

Python: Get all combinations of sequential elements of list

Given an array say x = ['A','I','R'] I would want output as an

[['A','I','R'],['A','I'],['I','R'],['A'],['I'],['R']]

What I don't want as output is :

[['A','I','R'],['A','I'],['I','R'],['A','R'],['A'],['I'],['R']]  # extra ['A','R'] which is not in sequence .

Below is the code which gives the output I don't want:

letter_list = [a for a in str]
all_word = []
for i in xrange(0,len(letter_list)):
    all_word = all_word + (map(list, itertools.combinations(letter_list,i))) # dont use append. gives wrong result.
all_word = filter(None,all_word) # remove empty combination
all_word = all_word + [letter_list] # add original list

My point is I only want combinations of sequences. Is there any way to use itertools or should I write custom function ?

Try to use yield :

x = ['A','I','R']

def groupme(x):
    s = tuple(x)
    for size in range(1, len(s) + 1):
        for index in range(len(s) + 1 - size):
            yield list(x[index:index + size])

list(groupme(x))

>>> [['A'], ['I'], ['R'], ['A', 'I'], ['I', 'R'], ['A', 'I', 'R']]

Yes, you can use itertools :

>>> x = ['A', 'I', 'R']
>>> xs = [x[i:j] for i, j in itertools.combinations(range(len(x)+1), 2)]
>>> xs
[['A'], ['A', 'I'], ['A', 'I', 'R'], ['I'], ['I', 'R'], ['R']]
>>> sorted(xs, key=len, reverse=True)
[['A', 'I', 'R'], ['A', 'I'], ['I', 'R'], ['A'], ['I'], ['R']]

Credit: answer by hochl

don't try to be so magical: two loops will do what you want; one over possible sequence starts, the inner over possible sequence lengths:

x = "AIR" # strings are iterables/sequences, too!
all_words = []
for begin in xrange(len(x)):
    for length in xrange(1,len(x) - begin+1):
        all_words.append(x[begin:begin+length])

using list comprehension:

letters=['A', 'I', 'R']
[letters[start:end+1] 
 for start in xrange(len(letters)) 
 for end in xrange(start, len(letters))]

[['A'], ['A', 'I'], ['A', 'I', 'R'], ['I'], ['I', 'R'], ['R']]

if it is important to have the order you proposed (from longest to shortest and when the same length by starting position) you can do instead:

[letters[start:start+l+1]
 for l in range(len(letters))[::-1]
 for start in xrange(len(letters)-l)]

[['A', 'I', 'R'], ['A', 'I'], ['I', 'R'], ['A'], ['I'], ['R']]

Just to address Holroy comment. If instead of using list comprehension you use a generator expression (just substituting external [] with () ) you would get a much less memory requiring code. But in this case you must be careful of not using the result more than once or for instance not trying to use list methods (such as len, or removing elements) on the result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM