What is the best way to generate all possible three letter strings? - python

I am generating all possible three letters keywords e.g. aaa, aab, aac.... zzy, zzz below is my code:
alphabets = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
keywords = []
for alpha1 in alphabets:
for alpha2 in alphabets:
for alpha3 in alphabets:
keywords.append(alpha1+alpha2+alpha3)
Can this functionality be achieved in a more sleek and efficient way?

keywords = itertools.product(alphabets, repeat = 3)
See the documentation for itertools.product. If you need a list of strings, just use
keywords = [''.join(i) for i in itertools.product(alphabets, repeat = 3)]
alphabets also doesn't need to be a list, it can just be a string, for example:
from itertools import product
from string import ascii_lowercase
keywords = [''.join(i) for i in product(ascii_lowercase, repeat = 3)]
will work if you just want the lowercase ascii letters.

You could also use map instead of the list comprehension (this is one of the cases where map is still faster than the LC)
>>> from itertools import product
>>> from string import ascii_lowercase
>>> keywords = map(''.join, product(ascii_lowercase, repeat=3))
This variation of the list comprehension is also faster than using ''.join
>>> keywords = [a+b+c for a,b,c in product(ascii_lowercase, repeat=3)]

from itertools import combinations_with_replacement
alphabets = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
for (a,b,c) in combinations_with_replacement(alphabets, 3):
print a+b+c

You can also do this without any external modules by doing simple calculation.
The PermutationIterator is what you are searching for.
def permutation_atindex(_int, _set, length):
"""
Return the permutation at index '_int' for itemgetter '_set'
with length 'length'.
"""
items = []
strLength = len(_set)
index = _int % strLength
items.append(_set[index])
for n in xrange(1,length, 1):
_int //= strLength
index = _int % strLength
items.append(_set[index])
return items
class PermutationIterator:
"""
A class that can iterate over possible permuations
of the given 'iterable' and 'length' argument.
"""
def __init__(self, iterable, length):
self.length = length
self.current = 0
self.max = len(iterable) ** length
self.iterable = iterable
def __iter__(self):
return self
def __next__(self):
if self.current >= self.max:
raise StopIteration
try:
return permutation_atindex(self.current, self.iterable, self.length)
finally:
self.current += 1
Give it an iterable object and an integer as the output-length.
from string import ascii_lowercase
for e in PermutationIterator(ascii_lowercase, 3):
print "".join(e)
This will start from 'aaa' and end with 'zzz'.

chars = range(ord('a'), ord('z')+1);
print [chr(a) + chr(b) +chr(c) for a in chars for b in chars for c in chars]

We could solve this without the itertools by utilizing two function definitions:
def combos(alphas, k):
l = len(alphas)
kRecur(alphas, "", l, k)
def KRecur(alphas, prfx, l, k):
if k==0:
print(prfx)
else:
for i in range(l):
newPrfx = prfx + alphas[i]
KRecur(alphas, newPrfx, l, k-1)
It's done using two functions to avoid resetting the length of the alphas, and the second function self-iterates itself until it reaches a k of 0 to return the k-mer for that i loop.
Adopted from a solution by Abhinav Ramana on Geeks4Geeks

Well, i came up with that solution while thinking about how to cover that topic:
import random
s = "aei"
b = []
lenght=len(s)
for _ in range(10):
for _ in range(length):
password = ("".join(random.sample(s,length)))
if password not in b:
b.append("".join(password))
print(b)
print(len(b))
Please let me describe what is going on inside:
Importing Random,
creating a string with letters that we want to use
creating an empty list that we will use to put our combinations in
and now we are using range (I put 10 but for 3 digits it can be less)
next using random.sample with a list and list length we are creating letter combinations and joining it.
in next steps we are checking if in our b list we have that combination - if so, it is not added to the b list. If current combination is not on the list, we are adding it to it. (we are comparing final joined combination).
the last step is to print list b with all combinations and print number of possible combinations.
Maybe it is not clear and most efficient code but i think it works...

print([a+b+c for a in alphabets for b in alphabets for c in alphabets if a !=b and b!=c and c!= a])
This removes the repetition of characters in one string

Related

Cannot find glitch in program using recursion for multible nested for-loops

alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z']
endlist = []
def loopfunc(n, lis):
if n ==0:
endlist.append(lis[0]+lis[1]+lis[2]+lis[3]+lis[4])
for i in alphabet:
if n >0:
lis.append(i)
loopfunc(n-1, lis )
loopfunc(5, [])
This program is supposed to make endlist be:
endlist = [aaaaa, aaaab, aaaac, ... zzzzy, zzzzz]
But it makes it:
endlist = [aaaaa, aaaaa, aaaaa, ... , aaaaa]
The lenght is right, but it won't make different words. Can anyone help me see why?
The only thing you ever add to endlist is the first 5 elements of lis, and since you have a single lis that is shared among all the recursive calls (note that you never create a new list in this code other than the initial values for endlist and lis, so every append to lis is happening to the same list), those first 5 elements are always the a values that you appended in your first 5 recursive calls. The rest of the alphabet goes onto the end of lis and is never reached by any of your other code.
Since you want string in the end, it's a little easier just to use strings for collecting your items. This avoids the possibility of shared mutable references which is cause your issues. With that the recursion becomes pretty concise:
alphabet = 'abcdefghijklmnopqrstuvwxyz'
def loopfunc(n, lis=""):
if n < 1:
return [lis]
res = []
for a in alphabet:
res.extend(loopfunc(n-1, lis + a))
return res
l = loopfunc(5)
print(l[0], l[1], l[-1], l[-2])
# aaaaa aaaab zzzzz zzzzy
Note that with n=5 you'll have almost 12 million combinations. If you plan on having larger n values, it may be worth rewriting this as a generator.

How do I recursively reverse a list in python without an aux fnc

Write a function that reverses a string. The input string is given as an array of characters char[].
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
You may assume all the characters consist of printable ascii characters.
Example:
Input: ["h","e","l","l","o"]
Output: ["o","l","l","e","h"]
I'm fairly new to recursion so I looked up some possible solutions but I'm not sure why this one isn't outputting the desired result as it looks like it runs.
class Solution(object):
def reverseString(self, s):
"""
:type s: List[str]
:rtype: None Do not return anything, modify s in-place instead.
"""
if not s:
return []
else:
return [s[-1]] + self.reverseString(s[:-1])
This is not quite as elegant of a solution, but it works.
def rev(arr, i=0):
if i >= len(arr) // 2:
return
arr[i], arr[-(i + 1)] = arr[-(i + 1)], arr[i]
rev(arr, i + 1)
test = ["t", "e", "s", "t"]
>>> test
['t', 'e', 's', 't']
>>> rev(test)
['t', 's', 'e', 't']
Recursive implementation :
>>> L = ["h","e","l","l","o"]
>>> L
['h', 'e', 'l', 'l', 'o']
reverse = lambda L: (reverse (L[1:]) + L[:1] if L else [])
>>> print(reverse(L))
['o', 'l', 'l', 'e', 'h']

Iterate through letters of an unknown length of digits

Okay... I need to iterate through strings with arbitrary lengths. Since I don't know how to explain this too well, I mean like this:
def zip(string1,string1):
...
and when called with "a" and "ad" it would return a list:
>>>zip("a","ad")
["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","aa","ab","ac","ad"]
I've tried using map(chr,range(ord('a'),ord('nb')+1)) but I get TypeError: ord() expected a character, but string of length 2 found, and I don't know where to go from here. Any ideas?
That's it:
def zip_(start, end):
def __inc(s):
if not s:
return "a"
elif s[-1] != "z":
return s[:-1] + chr(ord(s[-1]) + 1)
else:
return __inc(s[:-1]) + "a"
s = start
yield s
while s != end:
s = __inc(s)
yield s
print list(zip_("a", "ad"))
A few comments:
Don't use the word zip as a name of a variable or a function, because it's already reserved.
In the solution zip_ is a generator. I did it in order to not keep too much data in memory. If you need an exact list, just convert it as I've done in the print-statement.
In case of wrong arguments the function may go into an infinite loop. For example, if you call zip_("b", "a"). But actually it's easy to fix by adding a few lines if it's necessary.
This is a base-26 number system and here is how I would solve it. And also zip is a python built-in function, probably better not to redefine it.
def alphaToNumber(s):
r = 0
for x in s:
r *= 26
r += ord(x) - 96
return r
def numberToAlpha(n, result):
head = (n - 1) // 26
tail = chr((n - 1) % 26 + 97)
if head == 0:
return tail + result
else:
return numberToAlpha(head, tail + result)
def gen(start, end):
start_n = alphaToNumber(start)
end_n = alphaToNumber(end)
return [numberToAlpha(x, "") for x in range(start_n, end_n + 1)]
print(gen("a", "ad"))
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'aa', 'ab', 'ac', 'ad']

Split a string in Python having parenthesis (multiple splitters)

I have a string, for example:
"ab(abcds)kadf(sd)k(afsd)(lbne)"
I want to split it to a list such that the list is stored like this:
a
b
abcds
k
a
d
f
sd
k
afsd
lbne
I need to get the elements outside the parenthesis in separate rows and the ones inside it in separate ones.
I am not able to think of any solution to this problem.
You can use iter to make an iterator and use itertools.takewhile to extract the strings between the parens:
it = iter(s)
from itertools import takewhile
print([ch if ch != "(" else "".join(takewhile(lambda x: x!= ")",it)) for ch in it])
['a', 'b', 'abcds', 'k', 'a', 'd', 'f', 'sd', 'k', 'afsd', 'lbne']
If ch is not equal to ( we just take the char else if ch is a ( we use takewhile which will keep taking chars until we hit a ) .
Or using re.findall get all strings starting and ending in () with \((.+?))` and all other characters with :
print([''.join(tup) for tup in re.findall(r'\((.+?)\)|(\w)', s)])
['a', 'b', 'abcds', 'k', 'a', 'd', 'f', 'sd', 'k', 'afsd', 'lbne']
You just need to use the magic of 're.split' and some logic.
import re
string = "ab(abcds)kadf(sd)k(afsd)(lbne)"
temp = []
x = re.split(r'[(]',string)
#x = ['ab', 'abcds)kadf', 'sd)k', 'afsd)', 'lbne)']
for i in x:
if ')' not in i:
temp.extend(list(i))
else:
t = re.split(r'[)]',i)
temp.append(t[0])
temp.extend(list(t[1]))
print temp
#temp = ['a', 'b', 'abcds', 'k', 'a', 'd', 'f', 'sd', 'k', 'afsd', 'lbne']
Have a look at difference in append and extend here.
I hope this helps.
You have two options. The really easy one is to just iterate over the string. For example:
in_parens=False
buffer=''
for char in my_string:
if char =='(':
in_parens=True
elif char==')':
in_parens = False
my_list.append(buffer)
buffer=''
elif in_parens:
buffer+=char
else:
my_list.append(char)
The other option is regex.
I would suggest regex. It is worth practicing.
Try: Python re. If you are new to re it may take a bit of time but you can do all kind of string manipulations once you get it.
import re
search_string = 'ab(abcds)kadf(sd)k(afsd)(lbne)'
re_pattern = re.compile('(\w)|\((\w*)\)') # Match single character or characters in parenthesis
print [x if x else y for x,y in re_pattern.findall(search_string)]

How to randomly partition a list into n nearly equal parts?

I have read the answers to the Slicing a list into n nearly-equal-length partitions [duplicate] question.
This is the accepted answer:
def partition(lst, n):
division = len(lst) / float(n)
return [ lst[int(round(division * i)): int(round(division * (i + 1)))] for i in xrange(n) ]
I am wondering, how does one modify these solutions in order to randomly assign items to a partition as opposed to incremental assignment.
Call random.shuffle() on the list before partitioning it.
Complete 2018 solution (python 3.6):
import random
def partition (list_in, n):
random.shuffle(list_in)
return [list_in[i::n] for i in range(n)]
Beware! this may mutate your original list
shuffle input list.
First you randomize the list and then you split it in n nearly equal parts.
Shuffling the list doesn't preserve order. You could do something like this instead (pretty easy to adapt to more than two parts). Completely untested.
from __future__ import annotations
from typing import TypeVar
import random
T = TypeVar("T")
def partition_list(s: list[T]) -> tuple[list[T], list[T]]:
"""
Randomly partition a list into two lists, preserving order. The number to
take is drawn from a uniform distribution.
"""
len_a = random.randint(0, len(s))
len_b = len(s) - len_a
put_in_a = [True] * len_a + [False] * len_b
random.shuffle(put_in_a)
a: list[T] = []
b: list[T] = []
for val, in_a in zip(s, put_in_a):
if in_a:
a.append(val)
else:
b.append(val)
return a, b
The random partition that also preserves the order:
def partition_preserve_order(list_in, n):
indices = list(range(len(list_in)))
shuffle(indices)
index_partitions = [sorted(indices[i::n]) for i in range(n)]
return [[list_in[i] for i in index_partition]
for index_partition in index_partitions]
(that is we shuffle the indices then sort them within the partitions)
example:
random_partition_preserve_order(list('abcdefghijklmnopqrstuvxyz'), 3)
# [
# ['c', 'd', 'g', 'm', 'p', 'r', 'v', 'x', 'y'],
# ['b', 'e', 'h', 'k', 'o', 'q', 't', 'u'],
# ['a', 'f', 'i', 'j', 'l', 'n', 's', 'z']
# ]

Categories