通过随机字符生成生成随机名字太慢
我做了这个程序,它创建随机字母组成随机名字,但这个程序运行速度很慢。它会生成随机字符串,检查它们是否是有效的名称,然后检查它们是否与用户给出的名称相匹配。通过随机字符生成生成随机名字太慢
我试过Cython,但我注意到Cython只支持Python 2.x.我使用Python 3.x.
下面的代码:
import sys
from random import randint
from datetime import datetime
lc_alphabet = "bcdfghjklmnpqrstvwxyz"
uc_alphabet = "BCDFGHJKLMNPQRSTVWXYZ"
lc_vocal = "aeiou"
uc_vocal = "AEIOU"
univ_list = []
verbose = False
def generator():
name_words = randint(4, 8)
finished_name = ""
for i in range(name_words):
io = randint(0, 3)
lc_alp_rand = randint(0, 20)
lc_vcl_rand = randint(0, 4)
lc_alp_i = lc_alphabet[lc_alp_rand]
lc_vcl_i = lc_vocal[lc_vcl_rand]
if io == 0 or io == 1:
finished_name += lc_alp_i
if io == 2 or io == 3:
finished_name += lc_vcl_i
return finished_name
def name_filtering():
while True:
this_name = generator()
VOCAL_WRONG = False
CONSONANT_WRONG = False
univ_wrong_point = 0
wrong_point = 0
for y in this_name:
if y in lc_vocal:
wrong_point += 1
if wrong_point >= len(this_name):
univ_wrong_point += 1
if verbose is True:
print("ALL VOCAL DETECTED " + this_name)
VOCAL_WRONG = True
wrong_point_2 = 0
for z in range(len(this_name)):
if this_name[z] in lc_alphabet:
wrong_point_2 += 1
if wrong_point_2 == len(this_name):
univ_wrong_point += 1
if verbose is True:
print("ALL CONSONANT DETECTED " + this_name)
CONSONANT_WRONG = True
for v in range(len(this_name)-1):
if this_name[v] in lc_vocal and this_name[v+1] in lc_vocal:
univ_wrong_point += 1
if verbose is True and VOCAL_WRONG is False:
print("VOCAL SIDE BY SIDE DETECTED " + this_name)
VOCAL_WRONG = True
if this_name[0] in lc_alphabet and this_name[1] in lc_alphabet and this_name[2] in lc_alphabet:
univ_wrong_point += 1
if verbose is True and CONSONANT_WRONG is False:
print("3 CONSONANT SIDE BY SIDE DETECTED " + this_name)
CONSONANT_WRONG = True
if this_name[1] in lc_alphabet and this_name[2] in lc_alphabet and this_name[3] in lc_alphabet:
univ_wrong_point += 1
if verbose is True and CONSONANT_WRONG is False:
print("3 CONSONANT SIDE BY SIDE DETECTED " + this_name)
CONSONANT_WRONG = True
if this_name[0] in lc_alphabet and this_name[1] in lc_alphabet and this_name[2] in lc_alphabet and \
this_name[3] in lc_alphabet:
univ_wrong_point += 1
if verbose is True and CONSONANT_WRONG is False:
print("4 CONSONANT SIDE BY SIDE DETECTED " + this_name)
CONSONANT_WRONG = True
if len(this_name) > 5:
if this_name[2] in lc_alphabet and this_name[3] in lc_alphabet and this_name[4] in lc_alphabet and \
this_name[5] in lc_alphabet:
univ_wrong_point += 1
if verbose is True and CONSONANT_WRONG is False:
print("4 CONSONANT SIDE BY SIDE DETECTED " + this_name)
CONSONANT_WRONG = True
if univ_wrong_point == 0:
return this_name
def search_name(txt):
disDate = str(datetime.now())
counter = 0
number = 0
while True:
name = name_filtering()
name_length = len(name)
std_space = 10
fin_space = std_space - name_length
the_space = " " * fin_space
if counter == 0:
print(str(number) + "| ", end="")
print(name + the_space, end="")
counter += 1
if counter == 10:
print()
counter = 0
number += 1
if name == txt:
print()
print()
print("Name " + txt + " FOUNDED on Number " + str(number))
print(disDate)
print(str(datetime.now()))
break
sys.stdout.flush()
def check_name(this_name):
univ_wrong_point = 0
wrong_point = 0
for y in this_name:
if y in lc_vocal:
wrong_point += 1
if wrong_point >= len(this_name):
univ_wrong_point += 1
if verbose is True:
print("ALL VOCAL DETECTED " + this_name)
wrong_point_2 = 0
for z in range(len(this_name)):
if this_name[z] in lc_alphabet:
wrong_point_2 += 1
if wrong_point_2 == len(this_name):
univ_wrong_point += 1
if verbose is True:
print("ALL CONSONANT DETECTED " + this_name)
for v in range(len(this_name) - 1):
if this_name[v] in lc_vocal and this_name[v + 1] in lc_vocal:
univ_wrong_point += 1
if verbose is True:
print("VOCAL SIDE BY SIDE DETECTED " + this_name)
if this_name[0] in lc_alphabet and this_name[1] in lc_alphabet and this_name[2] in lc_alphabet:
univ_wrong_point += 1
if verbose is True:
print("3 CONSONANT SIDE BY SIDE DETECTED " + this_name)
if this_name[1] in lc_alphabet and this_name[2] in lc_alphabet and this_name[3] in lc_alphabet:
univ_wrong_point += 1
if verbose is True:
print("3 CONSONANT SIDE BY SIDE DETECTED " + this_name)
if this_name[0] in lc_alphabet and this_name[1] in lc_alphabet and this_name[2] in lc_alphabet and \
this_name[3] in lc_alphabet:
univ_wrong_point += 1
if verbose is True:
print("4 CONSONANT SIDE BY SIDE DETECTED " + this_name)
if len(this_name) > 5:
if this_name[2] in lc_alphabet and this_name[3] in lc_alphabet and this_name[4] in lc_alphabet and \
this_name[5] in lc_alphabet:
univ_wrong_point += 1
if verbose is True:
print("4 CONSONANT SIDE BY SIDE DETECTED " + this_name)
if len(this_name) > 8:
print("TOO LONG (more than 8 letter)")
univ_wrong_point += 1
if len(this_name) < 4:
print("TOO FEW (fewer than 4 letter)")
univ_wrong_point += 1
if univ_wrong_point == 0:
print("this name match criteria")
else:
print("this name does not match criteria")
check_name(str(input("Check Name Criteria : ")))
search_name(str(input("Search Name in 4 words : ")))
我将不胜感激找出这个代码是如何被加快。我怀疑name_filtering
正在让它变慢。
有几件事情可以用你的代码完成。你必须的check_name
逻辑两次,例如 - 一个小的修改,我可以修改name_filtering
这样:
def name_filtering():
while True:
this_name = name_generator()
if check_name(this_name):
return this_name
我也减少了一些逻辑的check_name
- 例如,你不需要同时检查4和3奔跑,因为你会发现3运行,如果有4.
我还实施了集会员资格测试,并增加了一些为简洁循环运行,并串插,这导致加.format
到一些加速。然而真正的杀手是这样的:name_filtering
实际上完全是冗余的。您可以使用您的条件制作generator
(我已将其重命名为name_generator
,因为生成器已经是Python中的东西了,并且name_generator
会告诉您更多关于它的作用)始终会生成有效的名称。你的标准是只能有一个连续的元音,在name_generator
内连续1-2个辅音很容易做到。您只需添加一个随机元音,然后添加一个或两个随机辅音。
import sys
import random
import itertools
from datetime import datetime
#strings that can use random.choice
lc_consonants = "bcdfghjklmnpqrstvwxyz"
lc_vowel = "aeiou"
#sets that support fast membership testing
set_lc_consonants = set("bcdfghjklmnpqrstvwxyz")
set_lc_vowel = set("aeiou")
verbose = False
#name generator which now always produces a valid name
def name_generator():
finished_name = []
desired_characters = random.randrange(4, 9)
next_is_consonant = random.random() < 0.7
while len(finished_name) < desired_characters:
if next_is_consonant:
finished_name.extend(random.choice(lc_consonants) for _ in range(random.randrange(1, 3)))
else:
finished_name.append(random.choice(lc_vowel))
next_is_consonant = not next_is_consonant
return ''.join(finished_name)
#this is now redundant:
def name_filtering():
while True:
this_name = name_generator()
if check_name(this_name):
return this_name
#shortened logic: if a run of 3 is not present, we know a run of more than 3 is also not present
def check_name(this_name):
name_len = len(this_name)
VOWEL_WRONG = False
CONSONANT_WRONG = False
univ_wrong_point = 0
wrong_point = 0
wrong_point_2 = 0
for i in range(name_len - 1):
if all(this_name[i + j] in set_lc_vowel for j in range(2)):
if verbose and VOWEL_WRONG :
#str.format for interpolation from now on
print("VOWEL SIDE BY SIDE DETECTED {}".format(this_name))
return False
for i in range(name_len - 2):
if all(this_name[i + j] in set_lc_consonants for j in range(3)):
if verbose:
print("3 consonants side by side in {}".format(consonant_run))
return False
return True
def search_name(txt):
#no need for str conversion
start_date = datetime.now()
std_space = 10
#counter is implemented by itertools
for counter in itertools.count():
name = name_generator()
#use modular arithmetic rather than extra assignments
if counter % 10 == 0:
print("\n{}| ".format(counter // 10), end="")
#use str.format for space-filling rather than arithmetic
print("{: <{}}".format(name, std_space), end="")
if name == txt:
print("\n\nName {} FOUND on Number {}".format(txt, number))
#print automatically converts a datetime to a string
print(start_date)
print(datetime.now())
break
此代码现在是一个相当快一点 - 我测试了它这样的:
$ time python name_generator.py izaak | head -10000 | wc -l
在这里我修改了它,所以你可以到search
用于提供一个名称。我提供了我自己的(无效的D :)名称,并让它搜索10000行。用您的原始代码花了大约11秒,修改后的版本花费了1秒。
这实际上是更先进的,而我仍然在这里和那里使用基本的编程,例如我仍然使用基本的操作符。我明白了,这是天才谢谢你! – Wowotek
我用lc_alphabet只是普通可变像这样'lc_alphabet = “bcdfghjklmnpqrstvwxyz”' – Wowotek
做出一个'set':'lc_alphabet =集( “bcdfghjklmnpqrstvwxyz”)',并再次测试它。可以改进一点,而且很容易做到。 –
@ Jean-FrançoisFabre显然它不支持索引。 – Wowotek