Another IndexError with python - python

This is supposed to become a random name generator in the end, all the random part is working. Only problem is that it is REALLY random, getting weird stuff like aaaaaaaa etc.
So I'm trying to add a rule to not allow 2 vowels after each other (same goes with consonants).
So yeah, guys please help me out here. I've been looking throu' this code for 2 hours now and I cant find the problem.
Just pasting my entire code here.
import random
import string
import numpy as np
from sys import argv
import csv
# abcdefghijklmnopqrstuvwxyz
# Example output: floke fl0ke flok3 fl0k3
#
class facts:
kons = list('bcdfghjklmnpqrstvwxz') #20
voks = list('aeiouy') #6
abc = list('abcdefghijklmnopqrstuvwxyz')
def r_trfa(): #True Or False (1/0)
x = random.randrange(0, 2)
return x;
def r_kons(): #Konsonant
y = random.randrange(0, 20)
x = facts.kons[y]
return x;
def r_vok(): #Vokal
y = random.randrange(0, 6)
x = facts.voks[y]
return x;
def r_len(): #Langd
x = random.randrange(4, 8)
return x;
def r_type():
x = random.randrange(1, 4)
return x;
def r_structure(length): #Skapar strukturen
y = r_type()
if y == 0:
no1 = 1
else:
no1 = 2
i = 0
x = [no1]
y = r_type()
if not no1 == y:
x.append(y)
while i < length:
y = r_type()
if not x[i] == y:
x.append(y)
i = i + 1
x2 = list(x)
return x2;
def name(): #Final product
struct = r_structure(r_len())
name = struct

You've got several bugs. For example, you're checking the value y against 0 even though it is always in the range 1-4, probably unintended behavior. Furthermore, you never actually call a function that gets you a character, and you never create a string. Thus it's not clear what you're trying to do.
Here's how I'd rewrite things based on my guess of what you want to do.
import random, itertools
voks = frozenset('aeiouy')
abc = 'abcdefghijklmnopqrstuvwxyz'
def r_gen():
last=None #both classes ok
while 1:
new = random.choice(abc)
if (new in voks) != last:
yield new
last = (new in voks)
def name(): #Final product
length = random.randrange(4, 8)
return ''.join(itertools.islice(r_gen(), length))

The problem you're having is that your loop increments i always, but only adds an additional value to your x list if the random value doesn't match x[i]. This means that if you get several matches in a row, i may become larger than the largest index into x and so you'll get an IndexError exception.
I'm not entirely sure I understand what you're trying to do, but I think this will do something similar to your current r_structure function:
def r_structure(length):
"""Returns a list of random "types", avoiding any immediate repeats"""
x = [r_type()]
while len(x) < length:
y = r_type()
if y != x[-1]: # check against the last item in the list
x.append(y)
return x
If your goal is simply to randomly generate a sequence of alternating vowels and consonants, there's an easier way than what you seem to be doing. First off, you can use random.choice to pick your characters. Further, rather than picking many letters and rejecting ones that are of the wrong type, you can simply pick from one string, then pick from the other, for as long as you need:
import random
def alternating_characters(length):
characters = ["aeiouy", "bcdfghjklmnpqrstvwxz"]
char_type = random.randrange(2) # pick a random letter type to start with
results = []
while len(char_list) < length:
results.append(random.choice(characters[char_type])) # pick random char
char_type = 1-char_type # pick from the other list next time
return "".join(char_list)

Well it's unclear what you want to do.. As the conditions on vowels and consonants is the same, so why do you need to differentiate between them?
So all you need to do is take a random letter and check that it doesn't match with the last letter.
Here's some code:
import random
abc = 'abcdefghijklmnopqrstuvwxyz'
def gen_word(length):
last = ''
while length > 0:
l = random.choice(abc)
if l != last:
length -= 1
yield l
if __name__ == '__main__':
word = ''.join(gen_word(10))
print word

Related

Generate format following strings - random order

The Problem at hand
Currently, I am working towards making a code generator for reasons unnessesary to the question.
The Codes follow the format of 00|letter|8string mix|letter
Examples of expected end results are such:
00b06c1161bc
00aee797645b
00c435ab439e
00da494a229a
A quick breakdown of the middle 8 section string results in the requirement of a maximum of two alpha-characters and 6 numbers that can be in random order.
While Im having difficulty with this, there becomes the added problem of the limited letters accepted. These are the letters, a,b,c,d,e, and f
I've made a list (acceptedChars=["a","b","c","d","e","f"]) for the generator to pull from, however how to allow it to use this towards generation following the requirements I am unsure of how to pull off.
Any info on this would be wonderful, if you have any questions, comment and I will be sure to respond to it.
Here'a full implementation of the code using random function.
This code will generate you 100 random 12 char codes.
The below code also addresses the requirement of a maximum of two alpha-characters and 6 numbers that can be in random order
import random
acceptedChars = list('abcdef')
acceptedDigit = list('0123456789')
for i in range(100):
secretCode = '00' + random.choice(acceptedChars)
charCount = digitCount = 0
pos1 = random.randint(1,8)
pos2 = pos1
while pos2 == pos1: pos2 = random.randint(1,8)
for i in range(1,9):
if i in (pos1,pos2):
secretCode += random.choice(acceptedChars)
else:
secretCode += random.choice(acceptedDigit)
secretCode += random.choice(acceptedChars)
print (secretCode)
Sample output of the random codes (generated 10):
00e89642be3c
00ba75d2130e
00b56c9b906b
00da9294e87c
00b3664ce97f
00c4b6681a3e
00e6699f75cf
00d369d07a0a
00ce653a228f
00d5665f95bd
I think random.choice is what you want:
import random
acceptedChars = ["a","b","c","d","e","f"]
x = random.choice(acceptedChars)
y = random.choice(acceptedChars)
Check this whole code for your problem. Maybe you find something useful. I made it in less complexity than O(n2).
It is the program of random string generation for verification.
This code also fulfills the maximum 2 alpha requirements.
import random
def code():
acceptedChars=["a","b","c","d","e","f"]
first = "00"
second = random.choice(acceptedChars)
third = ""
fourth = random.choice(acceptedChars)
# for third part
slot = random.randint(0,2)
if (slot == 2):
number = str(random.randint(100000,1000000))
alpha1 = random.choice(acceptedChars)
alpha2 = random.choice(acceptedChars)
part1 = random.randint(0,6)
part2 = random.randint(part1,6)
third = number[:part1] + alpha1 + number[part1:part2] + alpha2 + number[part2:]
elif (slot == 1):
number = str(random.randint(1000000,10000000))
alpha = random.choice(acceptedChars)
slot = random.randint(0,8)
third = number[:slot] + alpha + number[slot:]
else:
third = str(random.randint(10000000,100000000))
return first + second + third + fourth
print(code())
Hope it helps.
Output looks like:
00d65262056f
00a317c8015e
00a334564ecf
00e14a657d9c
import string
import random
allowed_chars = string.ascii_letters[:6]
expression = ''.join(random.choices(allowed_chars + string.digits, k=8))
print(f"The generator is 00{str(expression)}")

Python - multiple combinations maths question

I'm trying to make a program that lists all the 64 codons/triplet base sequences of DNA...
In more mathematical terms, there are 4 letters: A, T, G and C.
I want to list all possible outcomes where there are three letters of each and a letter can be used multiple times but I have no idea how!
I know there are 64 possibilities and I wrote them all down on paper but I want to write a program that generates all of them for me instead of me typing up all 64!
Currently, I am at this point but I have most surely overcomplicated it and I am stuck:
list = ['A','T','G','C']
list2 = []
y = 0
x = 1
z = 2
skip = False
back = False
for i in range(4):
print(list[y],list[y],list[y])
if i == 0:
skip = True
else:
y=y+1
for i in range(16):
print(list[y],list[y],list[x])
print(list[y],list[x], list[x])
print(list[y],list[x], list[y])
print(list[y],list[x], list[z])
if i == 0:
skip = True
elif z == 3:
back = True
x = x+1
elif back == True:
z = z-1
x = x-1
else:
x = x+1
z = z+1
Any help would be much appreciated!!!!
You should really be using itertools.product for this.
from itertools import product
l = ['A','T','G','C']
combos = list(product(l,repeat=3 ))
# all 64 combinations
Since this produces an iterator, you don't need to wrap it in list() if you're just going to loop over it. (Also, don't name your list list — it clobbers the build-in).
If you want a list of strings you can join() them as John Coleman shows in a comment under your question.
list_of_strings = ["".join(c) for c in product(l,repeat=3) ]
Look for for pemuations with repetitions there tons of code available for Python .
I would just use library , if you want to see how they implemented it look inside the library . These guys usually do it very efficiency
import itertools
x = [1, 2, 3, 4, 5, 6]
[p for p in itertools.product(x, repeat=2)]

Changing version number to single digits python

I have a version number in a file like this:
Testing x.x.x.x
So I am grabbing it off like this:
import re
def increment(match):
# convert the four matches to integers
a,b,c,d = [int(x) for x in match.groups()]
# return the replacement string
return f'{a}.{b}.{c}.{d}'
lines = open('file.txt', 'r').readlines()
lines[3] = re.sub(r"\b(\d+)\.(\d+)\.(\d+)\.(\d+)\b", increment, lines[3])
I want to make it so if the last digit is a 9... then change it to 0 and then change the previous digit to a 1. So 1.1.1.9 changes to 1.1.2.0.
I did that by doing:
def increment(match):
# convert the four matches to integers
a,b,c,d = [int(x) for x in match.groups()]
# return the replacement string
if (d == 9):
return f'{a}.{b}.{c+1}.{0}'
elif (c == 9):
return f'{a}.{b+1}.{0}.{0}'
elif (b == 9):
return f'{a+1}.{0}.{0}.{0}'
Issue occurs when its 1.1.9.9 or 1.9.9.9. Where multiple digits need to rounded. How can I handle this issue?
Use integer addition?
def increment(match):
# convert the four matches to integers
a,b,c,d = [int(x) for x in match.groups()]
*a,b,c,d = [int(x) for x in str(a*1000 + b*100 + c*10 + d + 1)]
a = ''.join(map(str,a)) # fix for 2 digit 'a'
# return the replacement string
return f'{a}.{b}.{c}.{d}'
If your versions are never going to go beyond 10, it is better to just convert it to an integer, increment it and then convert back to a string.
This allows you to go up to as many version numbers as you require and you are not limited to thousands.
def increment(match):
match = match.replace('.', '')
match = int(match)
match += 1
match = str(match)
output = '.'.join(match)
return output
Add 1 to the last element. If it's more than 9, set it to 0 and do the same for the previous element. Repeat as necessary:
import re
def increment(match):
# convert the four matches to integers
g = [int(x) for x in match.groups()]
# increment, last one first
pos = len(g)-1
g[pos] += 1
while pos > 0:
if g[pos] > 9:
g[pos] = 0
pos -= 1
g[pos] += 1
else:
break
# return the replacement string
return '.'.join(str(x) for x in g)
print (re.sub(r"\b(\d+)\.(\d+)\.(\d+)\.(\d+)\b", increment, '1.8.9.9'))
print (re.sub(r"\b(\d+)\.(\d+)\.(\d+)\.(\d+)\b", increment, '1.9.9.9'))
print (re.sub(r"\b(\d+)\.(\d+)\.(\d+)\.(\d+)\b", increment, '9.9.9.9'))
Result:
1.9.0.0
2.0.0.0
10.0.0.0

python intelligent hexadecimal numbers generator

I want to be able to generate 12 character long chain, of hexadecimal, BUT with no more than 2 identical numbers duplicate in the chain: 00 and not 000
Because, I know how to generate ALL possibilites, including 00000000000 to FFFFFFFFFFF, but I know that I won't use all those values, and because the size of the file generated with ALL possibilities is many GB long, I want to reduce the size by avoiding the not useful generated chains.
So my goal is to have results like 00A300BF8911 and not like 000300BF8911
Could you please help me to do so?
Many thanks in advance!
if you picked the same one twice, remove it from the choices for a round:
import random
hex_digits = set('0123456789ABCDEF')
result = ""
pick_from = hex_digits
for digit in range(12):
cur_digit = random.sample(hex_digits, 1)[0]
result += cur_digit
if result[-1] == cur_digit:
pick_from = hex_digits - set(cur_digit)
else:
pick_from = hex_digits
print(result)
Since the title mentions generators. Here's the above as a generator:
import random
hex_digits = set('0123456789ABCDEF')
def hexGen():
while True:
result = ""
pick_from = hex_digits
for digit in range(12):
cur_digit = random.sample(hex_digits, 1)[0]
result += cur_digit
if result[-1] == cur_digit:
pick_from = hex_digits - set(cur_digit)
else:
pick_from = hex_digits
yield result
my_hex_gen = hexGen()
counter = 0
for result in my_hex_gen:
print(result)
counter += 1
if counter > 10:
break
Results:
1ECC6A83EB14
D0897DE15E81
9C3E9028B0DE
CE74A2674AF0
9ECBD32C003D
0DF2E5DAC0FB
31C48E691C96
F33AAC2C2052
CD4CEDADD54D
40A329FF6E25
5F5D71F823A4
You could also change the while true loop to only produce a certain number of these based on a number passed into the function.
I interpret this question as, "I want to construct a rainbow table by iterating through all strings that have the following qualities. The string has a length of 12, contains only the characters 0-9 and A-F, and it never has the same character appearing three times in a row."
def iter_all_strings_without_triplicates(size, last_two_digits = (None, None)):
a,b = last_two_digits
if size == 0:
yield ""
else:
for c in "0123456789ABCDEF":
if a == b == c:
continue
else:
for rest in iter_all_strings_without_triplicates(size-1, (b,c)):
yield c + rest
for s in iter_all_strings_without_triplicates(12):
print(s)
Result:
001001001001
001001001002
001001001003
001001001004
001001001005
001001001006
001001001007
001001001008
001001001009
00100100100A
00100100100B
00100100100C
00100100100D
00100100100E
00100100100F
001001001010
001001001011
...
Note that there will be several hundred terabytes' worth of values outputted, so you aren't saving much room compared to just saving every single string, triplicates or not.
import string, random
source = string.hexdigits[:16]
result = ''
while len(result) < 12 :
idx = random.randint(0,len(source))
if len(result) < 3 or result[-1] != result[-2] or result[-1] != source[idx] :
result += source[idx]
You could extract a random sequence from a list of twice each hexadecimal digits:
digits = list('1234567890ABCDEF') * 2
random.shuffle(digits)
hex_number = ''.join(digits[:12])
If you wanted to allow shorter sequences, you could randomize that too, and left fill the blanks with zeros.
import random
digits = list('1234567890ABCDEF') * 2
random.shuffle(digits)
num_digits = random.randrange(3, 13)
hex_number = ''.join(['0'] * (12-num_digits)) + ''.join(digits[:num_digits])
print(hex_number)
You could use a generator iterating a window over the strings your current implementation yields. Sth. like (hex_str[i:i + 3] for i in range(len(hex_str) - window_size + 1)) Using len and set you could count the number of different characters in the slice. Although in your example it might be easier to just compare all 3 characters.
You can create an array from 0 to 255, and use random.sample with your list to get your list

ordered word perminuations in python

So my question is simple, and half of it is already working.
I need help with generating ordered word-permutations.
My code:
from os.path import isfile
from string import printable
def loadRuleSet(fileLocation):
rules = {}
assert isfile(fileLocation)
for x in open(fileLocation).read().split('\n'):
if not len(x) == 0:
data = x.split(':')
if not len(data[0]) == 0 or not len(data[1]) == 0:
rules[data[0]] = data[1]
return rules
class deform:
def __init__(self, ruleSet):
assert type(ruleSet) == dict
self.ruleSet = ruleSet
def walker(self, string):
spot = []
cnt = 0
for x in string:
spot.append((x, cnt))
cnt += 1
return spot
def replace_exact(self, word, position, new):
cnt = 0
newword = ''
for x in word:
if cnt == position:
newword += new
else:
newword += x
cnt+= 1
return newword
def first_iter(self, word):
data = []
pos = self.walker(word)
for x in pos:
if x[0] in self.ruleSet:
for y in self.ruleSet[x[0]]:
data.append(self.replace_exact(word, x[1], y))
return data
print deform({'a':'#A'}).first_iter('abac')
My current code does half of the job, but I've reached a "writer's block"
>>>deform({'a':'#'}).first_iter('aaa')
['#aa', 'a#a', 'aa#']
Here's the results from my currently made script.
What code is supposed to do is - take the word, and reorder it with other characters in the replacement. I've successfully made it do it with one character, but I need help with making all the results. For example:
['#aa', 'a#a', 'aa#', '##a', 'a##', '#a#']
In your case you can use permutations function which could return all possible orderings, no repeated elements.
from itertools import permutations
from operator import itemgetter
perm_one = sorted(set([''.join(x) for x in permutations('#aa')]))
perm_two = sorted(set([''.join(x) for x in permutations('##a')]), key=itemgetter(1))
print perm_one + perm_two
I divided it into two collections because they differ number of # and a characters.

Categories