Home > OS >  Finding all possible case permutations in Python with variations avoiding duplicates
Finding all possible case permutations in Python with variations avoiding duplicates

Time:01-25

Given a list of words and chars, I need to generate words variations (lowercase, uppercase, etc.) and all possible permutations avoiding duplicates (case-insensitive).

Example

words = ["one", "two"]
chars = ["!"]

Words variations:

one, One, ONE, oNE, two, Two, TWO, tWO

...and possible (incremental) permutations:

one, one!, !one, One, One!, !One, ONE, ONE!, !ONE, two, two! ...,
...onetwo, onetwo!, !onetwo, Onetwo, Onetwo!, !Onetwo, ...
...OneTwo, OneTwo!, !OneTwo, ...
...twoone, twoone!, !twoone, ...etc.

but not:

oneOne, oneONE, oneoNE, ...twoTwo, twoTWO, twotWO...

This is my Python code:


words = ["one", "two"]
chars = ["2022", "!", "_"]

file_permuted = "permuted_words.txt"

transformed_words = []
words_to_permute = []
permuted_words = []
counter = 0
total_counter = 0

for word in words:

    # Apply the case transformations: word, WORD, Word, wORD
    lowercase_all = word.lower()
    uppercase_all = word.upper()
    capitalize_first = word.capitalize()
    toggle_case =  capitalize_first.swapcase()

    # Add the transformed words to the list
    transformed_words.append(lowercase_all)
    transformed_words.append(uppercase_all)
    transformed_words.append(capitalize_first)
    transformed_words.append(toggle_case)

words_to_permute = transformed_words   chars

print("Generating permutations...")
with open(file_permuted, "w") as f:
    for i in range(1, len(words_to_permute)   1):
        for permutation in itertools.permutations(words_to_permute, i):
            len_set_permutation = len(set(list(map(lambda x: x.lower(), permutation))))
            if (len_set_permutation == len(permutation)):
                f.write("".join(permutation)   "\n")
                if (counter == 100):
                    total_counter  = counter
                    print('Processed {0} items'.format(str(total_counter)))
                    counter = 0

                counter  = 1

Please, suggest me a better/more elegant and efficient way.

CodePudding user response:

Here is the variations of lower/upper case letters for one word. It models the case depending on whether the bit is 1 or 0. (as suggested by Caridorc in the comments above).

s = 'one'

for i in range(2**len(s)):
    string = ''
    ii = i
    for j in range(len(s)-1,-1,-1): # start at the right
        bit = ii & 1;
    
        if bit == 1:
            string = s[j].upper()   string # build string from right to left
        else:
            string = s[j].lower()   string
        
        ii >>= 1 # shift bits (number) 1 to the right
        

    print(f'{i:0{len(s)}b}',string)

Prints:

000 one
001 onE
010 oNe
011 oNE
100 One
101 OnE
110 ONe
111 ONE

CodePudding user response:

Like this:

def word_casing (word):
    if 0 == len(word):
        yield ""
    else:
        char = word[0]
        for next_word in word_casing(word[1:]):
            yield char   next_word
            yield char.upper()   next_word

def word_casing_fn (word):
    def inner ():
        yield from word_casing(word)
    return inner

def char_listing_fn (char):
    def inner ():
        yield char
    return inner

def subsets (items):
    if 0 == len(items):
        yield []
    else:
        for s in subsets(items[1:]):
            yield s
            yield [items[0]]   s

def nonempty_subsets (items):
    for s in subsets(items):
        if 0 < len(s):
            yield s

def permutations (items):
    if 0 == len(items):
        yield []
    else:
        for i in range(len(items)):
            if 0 == i:
                for p in permutations(items[1:]):
                    yield [items[0]]   p
            else:
                (items[0], items[i]) = (items[i], items[0])
                for p in permutations(items[1:]):
                    yield [items[0]]   p
                (items[0], items[i]) = (items[i], items[0])

def list_fn_combinations (list_fns):
    if 1 == len(list_fns):
        for item in list_fns[0]():
            yield item
    elif 1 < len(list_fns):
        for item in list_fns[0]():
            for comb in list_fn_combinations(list_fns[1:]):
                yield item   comb

def all_combs (words, chars):
    list_fns = []
    for word in words:
        list_fns.append(word_casing_fn(word))
    for char in chars:
        list_fns.append(char_listing_fn(char))
    for s in nonempty_subsets(list_fns):
        for p in permutations(s):
            for c in list_fn_combinations(p):
                yield c


for w in all_combs(["one", "two"], ["!"]):
    print(w)
  • Related