2017-08-31 17 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'のことを確認してください。少し改善することができ、それは簡単です。 –

+0

@ Jean-FrançoisFabreそれは明らかにインデックス作成をサポートしていません。 – Wowotek

答えて

2

コードで実行できることがいくつかありました。次の例のように、二回check_nameのロジックを持っていた - 少しの変更で、私はこれにname_filteringを変更することができます:私もcheck_nameにロジックの一部を削減

def name_filtering(): 
    while True: 
     this_name = name_generator() 
     if check_name(this_name): 
      return this_name 

- 例えばあなたが、両方をチェックする必要はありません。 4のランがあれば3のランを見つけるでしょう。

メンバーシップテスト用のセットを実装し、簡略化のためにいくつかのループを追加し、文字列補間のために.formatを追加しました。いくつかのスピードアップ。しかし、実際の殺人者はこれでした:name_filteringは実際には完全に冗長です。あなたの基準を使用してgenerator(私はname_generatorに名前を変更しました。ジェネレータはすでにPythonの中にあるので、name_generatorは、いつも有効な名前を生成します)。あなたの基準は、連続する母音が1つしかないことがあり、連続する2つの子音が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 

このコードはかなり速くなりました - 私はこのようにそれをテスト:あなたはsearchに名前を提供できるように、私はそれを修正のだ

$ time python name_generator.py izaak | head -10000 | wc -l 

こちら。私は自分の(無効なD :)名を提供し、10000行を検索させました。元のコードでは約11秒かかっていましたが、変更されたバージョンでは1秒かかりました。 `lc_alphabet =セット( "bcdfghjklmnpqrstvwxyz")`と、再びそれをテスト:

+0

これは実際にはさらに進歩していますが、ここでも基本的なプログラミングを使用しています。私はアイデアを持って、これは天才ですありがとう! – Wowotek

関連する問題