Not the exercise. This lists every way to pick a team captain and then a vice captain from some names, which is the first two steps of an arrangement.
names = ["Ada", "Grace", "Linus"]
for i, captain in enumerate(names):
others = names[:i] + names[i + 1:] # everyone except the captain
for vice in others:
print(captain, "and", vice)
# Ada and Grace
# Ada and Linus
# Grace and Ada
# ... six pairs in all
- "Everyone except this one"
names[:i] + names[i + 1:] is the list with position i taken out. It is the smaller problem handed to the next step, and in the exercise the next step is a recursive call.
- Two loops for two places, and then you are stuck
Three places would need a third loop, and six letters six loops. Recursion replaces "one loop per place" with one function that handles however many places are left.
- Order comes from the loop
Because i goes left to right, the output is grouped by the first choice. The exercise’s order is exactly that, one level at a time.
Pick a first letter, arrange everything else, and put the first letter in front of each of those arrangements. Do it for each possible first letter.
Base case: "" returns [""]. Otherwise loop over positions i; the rest is text[:i] + text[i + 1:]. Keep a set of letters already used as first letter and skip any you have seen.
result = []; used = set(); for each i, letter: skip if letter in used; add it to used; for each tail in arrangements(rest): append letter + tail. Return result.
def arrangements(text): if not text: return [____] result, used = [], set() for i, letter in enumerate(text): if letter in ____: continue used.add(letter) for tail in arrangements(text[:i] + text[____:]): result.append(letter + tail) return result
def arrangements(text):
if not text:
return [""]
result, used = [], set()
for i, letter in enumerate(text):
if letter in used:
continue
used.add(letter)
for tail in arrangements(text[:i] + text[i + 1:]):
result.append(letter + tail)
return result
A second a in first place would start exactly the arrangements the first a already produced. Skipping it before recursing avoids the duplicates and the work of making them, at every level.
set(all orders) removes duplicates too, but only after building all of them, and it loses the order the contract asks for. "aaaaaaab" has 8 distinct arrangements and 40,320 orders with repeats.
There is one way to arrange no letters. Returning [] would leave nothing for the letter above to be put in front of, and every answer would come back empty.
The number of arrangements grows as a factorial: ten distinct letters already give 3,628,800. For anything beyond a handful, itertools.permutations produces them one at a time instead of building the whole list, and most real problems want the best arrangement, which needs a search that prunes, not a list of all of them.
- Yield the arrangements one at a time instead of returning a list.
- Return only the arrangements that are real words, given a set of words.
- Count the distinct arrangements with a formula, and check it against len(...).