Last active
March 3, 2022 13:27
-
-
Save orbyfied/5adb2b292a424d81e498874a1bca5190 to your computer and use it in GitHub Desktop.
Generates all possible variations of a word or sentence without duplicate elements.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# By orbyfied, (C) 2022 L | |
# | |
from abc import abstractmethod | |
import time | |
import math | |
# utility class for building strings | |
class StringBuffer: | |
@abstractmethod | |
def __init__(self): | |
pass | |
@abstractmethod | |
def __init__(self, str): | |
pass | |
def __str__(self): | |
return self.get() | |
@abstractmethod | |
def get(self): | |
pass | |
@abstractmethod | |
def append(self, toAppend): | |
pass | |
@abstractmethod | |
def delete(self, start, end): | |
pass | |
@abstractmethod | |
def trim(self, start, end): | |
pass | |
@abstractmethod | |
def clone(self): | |
pass | |
@abstractmethod | |
def close(self): | |
pass | |
# implementation of string buffer using | |
# string concatenation, inefficient, will be | |
# improved and deprecated soon. exports strings | |
class ConcatStringBuffer(StringBuffer): | |
def __init__(self): | |
self.str = "" | |
def __init__(self, str): | |
self.str = str | |
def get(self): | |
return self.str | |
def append(self, toAppend): | |
self.str += str(toAppend) | |
return self | |
def delete(self, start, end): | |
self.str = self.str[0:start] + self.str[end:] | |
return self | |
def trim(self, start, end): | |
self.str = self.str[start:end] | |
return self | |
def clone(self): | |
return ConcatStringBuffer(self.str) | |
def close(self): | |
pass | |
def chars_to_string(chars): | |
str = '' | |
for c in chars: | |
str += c | |
return str | |
# uses an internal character array to store | |
# the string. exports the character arrays as | |
# possibilities instead of strings. | |
class BufferedStringBuffer(StringBuffer): | |
def __init__(self): | |
self.chars = [] | |
def __init__(self, str): | |
if str is list: | |
self.chars = str | |
else: | |
self.chars = list(str) | |
def get(self): | |
return self.chars | |
def append(self, toAppend): | |
for c in toAppend: | |
self.chars.append(c) | |
return self | |
def clone(self): | |
return BufferedStringBuffer(self.chars) | |
# TODO: make more efficient string builder | |
# get word | |
word = input("input: ") | |
# output information | |
output = "" | |
count = 0 | |
# utility functions | |
# copies an array, uses references to the original objects | |
def copy_array(arr): | |
new_arr = [] | |
for e in arr: | |
new_arr.append(e) | |
return new_arr | |
# gets the given string as a char array | |
def get_string_as_chars(str): | |
chars = [] | |
for c in str: | |
chars.append(c) | |
# return chars | |
return list(str) | |
# gets the words in a given sentence with a space behind them | |
def get_words_in_sentence(str): | |
words = [] | |
for word in str.split(' '): | |
words.append(word + " ") | |
return words | |
# magic function(s) | |
def get_shuffeled_variations(input): | |
# parse input | |
if len(input) == 0: # check if we have input | |
return [], 0 | |
chars = None | |
if ' ' in input and not input[0] == '"': # sentence | |
chars = get_words_in_sentence(input) | |
else: | |
# if input follows { "..." } then { ... } will be extracted, | |
# instead of parsing it as a sentence for if you want to get_shuffele | |
# an input with spaces per character | |
if input[0] == '"' and input[len(input)-1] == '"': | |
input = input[1:len(input)-1] | |
chars = get_string_as_chars(input) | |
# initialize values | |
buffer = ConcatStringBuffer("") | |
depth = len(chars) - 1 | |
used = '' | |
possibilities = [] | |
# start recursion chair which will eventually | |
# generate all possibilities and return the result(s) | |
next_char(buffer, depth, chars, used, possibilities) | |
return possibilities, len(possibilities) | |
def next_char(buffer : StringBuffer, depth, chars, used, possibilities): | |
# clones the char array for local use and remove used char | |
charsClone = copy_array(chars) | |
try: | |
charsClone.remove(used) | |
except ValueError: | |
pass | |
# clone buffer for local use | |
usedBuffer = buffer.clone() | |
# iterate over possible characters | |
for c in charsClone: | |
# append to buffer | |
usedBuffer.append(c) | |
if depth != 0: # if depth isnt 0, continue | |
# DEBUG: print("depth: " + str(depth) + ", chars: " + str(charsClone)) | |
next_char(usedBuffer, depth - 1, charsClone, c, possibilities) | |
else: # else add it to the possibilities | |
possibilities.append(usedBuffer.get()) | |
# reset buffer | |
usedBuffer = buffer.clone() | |
# close buffer | |
usedBuffer.close() | |
# actually do the magic | |
print("> generating possibilities") | |
t1 = time.time() | |
possibilities, count = get_shuffeled_variations(word); | |
t2 = time.time() | |
# format output nicely | |
print("> formatting output") | |
i = 0 | |
for possibility in possibilities: | |
string = None | |
if type(possibility) != str: | |
string = chars_to_string(possibility) | |
else: | |
string = str(possibility) | |
output += "result: " + str(i) + " | " + string + "\n" | |
i += 1 | |
# print output | |
print(output[:len(output)-1]) | |
print("result-count: " + str(count)) | |
print("time-taken-to-generate: " + f'{((t2 - t1) * 1000):.2f}' + "ms") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment