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)