5

Let's say I have the word "apple", the set of letters ['a', 'l', 'e'] and the number of repetition 3. From this I'd like to create the following set: ['aaapple', 'aaappllle', 'aaappllleee', 'appllle', 'appllleee', 'appleee'].

Here is what I've already tried:

l = ['a', 'l', 'e']
word = "apple"

for i in range(0, len(l)):
    print wordWithDuplicatedLetters = "".join(3*c if c == l[i] else c for c in word)

But this doesn't match all the combinations, and itertools doesn't seem to offer the possibility I'm looking for.

SuperKogito
  • 2,998
  • 3
  • 16
  • 37
ooj-001
  • 180
  • 9

4 Answers4

3

I don't think your example output has all possible combinations, mine below I think has them all. The trick here is to go through all combinations of any size which the function all_combinations below does.

import itertools

repeat = ['a', 'l', 'e']
word = 'apple'

def all_combinations(itr):
    lst = list(itr)
    for r in range(1, len(lst) + 1):  # set start to 0 if want to include []
        for perm in itertools.combinations(lst, r=r):
            yield perm   # or use yield from in py3

def all_repeats():
    for rep in all_combinations(repeat):
        yield ''.join(char * 3 if char in rep else char for char in word)

print(list(all_repeats()))

output

['aaapple',
 'appllle',
 'appleee',
 'aaappllle',
 'aaappleee',
 'appllleee',
 'aaappllleee']
FHTMitchell
  • 11,793
  • 2
  • 35
  • 47
2

Try using this loop:

s = ''
for i in word:
    if i in l:
        s += (3 * i)
    else:
        s += i

Which can be a list comprehension:

s = ''.join([3 * i if i in l else i for i in word])

And now in both cases:

print(s)

Is:

aaappllleee

To fully answer your question

You would have to use:

import itertools

l = ['a', 'l', 'e']
word = 'apple'
l2 = []
for i in range(len(l)):
   for x in itertools.combinations(l, r=i+1):
       l2.append(x)
l3 = []
for lst in l2:
    l3.append(''.join(char * 3 if char in lst else char for char in word))

print(l3)

Output:

['aaapple', 'appllle', 'appleee', 'aaappllle', 'aaappleee', 'appllleee', 'aaappllleee']
U13-Forward
  • 69,221
  • 14
  • 89
  • 114
2

You can divide this problem into two steps. First, figuring out all possible subsets of positions that should be repeated. That is essentially a powerset taken from here with the empty case removed. Building it off of indices allows the solution to be robust against words that contain repeated letters for repetition.

Second, for each case in the powerset, build a valid string and display it.

from itertools import chain, combinations

def powerset_non_empty(iterable):
    """
    powerset with empty set skipped
    powerset([1,2,3]) -->  (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)
    """
    xs = list(iterable)
    # note we return a list, but could choose to return an iterator too
    return list(chain.from_iterable(combinations(xs,n) for n in range(1, len(xs)+1)))



l = ['a', 'l', 'e']
word = "apple"

indices = [i for i,c in enumerate(word) if c in l]
number_of_repetition = 3
powerset = powerset_non_empty(indices)

result = []
for index_tuple in powerset:
    s = ''
    for i, c in enumerate(word):
        if i in index_tuple:
            s += (number_of_repetition * c)
        else:
            s += c
    print(s)
    result.append(s)
#Output:
['aaapple',
 'appllle',
 'appleee',
 'aaappllle',
 'aaappleee',
 'appllleee',
 'aaappllleee']
Paritosh Singh
  • 6,034
  • 2
  • 14
  • 33
1

You can use a simple recursive generator function:

l = ['a', 'l', 'e']
word = "apple"
def combo(d, r, c):
  for i in l:
    if any(j[0] == i and len(j) < r for j in c):
      w = [j if j[0] != i or len(j) == r else j+([i]*(r-1)) for j in c]
      yield ''.join(map(''.join, w))
      if any(j[0] in l and len(j) < r for j in w):
        yield from combo(d, r, w)


print(list(combo(l, 3, [[i] for i in word])))

Output:

['aaapple', 'aaappllle', 'aaappllleee', 'aaappleee', 'aaappllleee', 'appllle', 'aaappllle', 'aaappllleee', 'appllleee', 'aaappllleee', 'appleee', 'aaappleee', 'aaappllleee', 'appllleee', 'aaappllleee']
Ajax1234
  • 69,937
  • 8
  • 61
  • 102