2017-08-31 190 views
-3

我做了這個程序,它創建隨機字母組成隨機名字,但這個程序運行速度很慢。它會生成隨機字符串,檢查它們是否是有效的名稱,然後檢查它們是否與用戶給出的名稱相匹配。通過隨機字符生成生成隨機名字太慢

我試過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

回答

2

有幾件事情可以用你的代碼完成。你必須的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