通过随机字符生成生成随机名字太慢

通过随机字符生成生成随机名字太慢

问题描述:

我做了这个程序,它创建随机字母组成随机名字,但这个程序运行速度很慢。它会生成随机字符串,检查它们是否是有效的名称,然后检查它们是否与用户给出的名称相匹配。通过随机字符生成生成随机名字太慢

我试过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正在让它变慢。

+0

我用lc_alphabet只是普通可变像这样'lc_alphabet = “bcdfghjklmnpqrstvwxyz”' – Wowotek

+0

做出一个'set':'lc_alphabet =集( “bcdfghjklmnpqrstvwxyz”)',并再次测试它。可以改进一点,而且很容易做到。 –

+0

@ Jean-FrançoisFabre显然它不支持索引。 – Wowotek

有几件事情可以用你的代码完成。你必须的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秒。

+0

这实际上是更先进的,而我仍然在这里和那里使用基本的编程,例如我仍然使用基本的操作符。我明白了,这是天才谢谢你! – Wowotek