简体   繁体   中英

Find all combinations of strings up to given character length

I've got a list of strings, for example: ['Lion','Rabbit','Sea Otter','Monkey','Eagle','Rat']

I'm trying to find out the total number of possible combinations of these items, where item order matters, and the total string length, when all strings are concatenated with comma separators is less than a given length.

So, for max total string length 14, I would need to count combinations such as (not exhaustive list):

  • Lion
  • Rabbit
  • Eagle,Lion
  • Lion,Eagle
  • Lion,Eagle,Rat
  • Eagle,Lion,Rat
  • Sea Otter,Lion
  • etc...

but it would not include combinations where the total string length is more than the 14 character limit, such as Sea Otter,Monkey

I know for this pretty limited sample it wouldn't be that hard to manually calculate or determine with a few nested loops, but the actual use case will be a list of a couple hundred strings and a much longer character limit, meaning the number of nested iterations to write manually would be extremely confusing...

I tried to work through writing this via Python's itertools, but keep getting lost as none of the examples I'm finding come close enough to what I'm needing, especially with the limited character length ( not limited number of items) and the need to allow repeated combinations in different orders.

Any help getting started would be great.

You can use itertools.combinations in a list comprehension that creates lists of max 3 items (more items will per definition be more than 14 characters combined), while filtering by total string length:

import itertools

lst = ['Lion','Rabbit','Sea Otter','Monkey','Eagle','Rat']
sorted_lst = sorted(lst, key=len)

#find max number of items
for n, i in enumerate(sorted_lst):
    if len(','.join(sorted_lst[:n+1])) > 14:
        items_limit = n+1
        break

[x for l in range(1, items_limit) for x in itertools.combinations(lst, l) if len(','.join(x))<15]

PS. use itertools.permutations if you need permutations (as in your sample output), your question is about combinations.

You can use a recursive generator function:

s, m_s = ['Lion','Rabbit','Sea Otter','Monkey','Eagle','Rat'], 14
def get_combos(d, c = []):
   yield ','.join(c) #yield back valid combination
   for i in range(len(d)):
       if d[i] not in c and len(','.join(c+[d[i]])) <= m_s:
          yield from get_combos(d[:i]+d[i+1:], c+[d[i]]) #found a new valid combination
       if len(d[i]) <= m_s:
          yield from get_combos(d[:i]+d[i+1:], [d[i]]) #ignore running combo and replace with new single string
       yield from get_combos(d[:i]+d[i+1:], c) #ignore string at current iteration of `for` loop and keep the running combination

_, *vals = set(get_combos(s))
print(vals)

Output:

['Rat,Rabbit', 'Lion,Rabbit', 'Eagle', 'Eagle,Lion,Rat', 'Monkey', 'Rabbit,Lion', 'Rat,Eagle', 'Sea Otter', 'Rat,Lion,Eagle', 'Monkey,Rat', 'Rabbit,Monkey', 'Sea Otter,Rat', 'Rabbit', 'Lion,Sea Otter', 'Rabbit,Eagle', 'Rat,Eagle,Lion', 'Rat,Sea Otter', 'Lion,Monkey', 'Eagle,Lion', 'Eagle,Rat', 'Lion,Eagle,Rat', 'Rat', 'Lion,Rat,Eagle', 'Eagle,Rabbit', 'Rat,Lion', 'Monkey,Eagle', 'Lion,Eagle', 'Eagle,Monkey', 'Monkey,Lion', 'Rat,Monkey', 'Sea Otter,Lion', 'Rabbit,Rat', 'Monkey,Rabbit', 'Eagle,Rat,Lion', 'Lion,Rat', 'Lion']       

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