有人可以帮我优化速度吗?

时间:2019-08-04 15:43:39

标签: python string optimization replace

以下是用于优化的代码:

import random

rules = {
    'X': {
        1: 'FXFF+',
        2: '+XXF]',
    }
}

L_string = 'FX'

def next_char(c):
    isrule = rules.get(c, c)
    if not isrule == c:
        _, choice = random.choice(list(rules.get(c).items()))
        return choice
    else:
        return isrule

for _ in range(6):
    L_string = ''.join([next_char(c) for c in L_string])

这里发生的是递归替换字符串中的字符。所以一步一步来:

  1. 以“ FX”开头
  2. 遍历字符串,并用随机规则(即“ FXFF +”或“ + XXF]”替换每个“ X”)。也就是说,每个“ X”规则都是随机的。这不是对字符串的每次运行的随机规则。
  3. 重复5次

最后,结果是一个较长的字符串,该字符串由开头的“ F”和规则“ FXFF +”,“ + XXF]”以某种随机组合组成。该表说明:

+------------+--------------------+--------------------+
| ITERATIONS |       STRING       | CHOSEN RULE VECTOR |
+------------+--------------------+--------------------+
|          1 | FFXFF+             | [rule 1]           |
|          2 | FF+XXF]FF+         | [rule 2]           |
|          3 | FF+FXFF++XXF]F]FF+ | [rule 1, rule 2]   |
|          4 | ...                | ...                |
|          5 | ...                | ...                |
+------------+--------------------+--------------------+

我读到re.sub是替换字符串最快的方法,但问题是每个字符的随机性。 Re.sub对此不起作用。

谢谢!

5 个答案:

答案 0 :(得分:2)

一个简单的〜4倍速度加快了消耗大部分运行时间的功能。

"$i"

优化的空间可能很大。也许某个地方的备忘通常可以为整个代码带来巨大的推动。

答案 1 :(得分:2)

假设字符“ {”和“}”未出现在模式中,则可以使用模板语言进行一些欺骗,然后再去除花括号。这在我的机器上快了2.5倍:

mydomains = []
with open("domains.txt") as f:
    for line in f:
        mydomains.append(line)

for item in mydomains:
    params = {
        'query': item,
                 'no.com',  # string for get info
        'se': 'g_it',  # string search engine
        'token': 'ad868fb77d43cfa57bc',  # string personal token
}

答案 2 :(得分:1)

具有递归的新方法,速度大约快1.6倍,另一种方法,在我的PC上速度快大约3.312倍

import re
from random import random, choice
from timeit import timeit
from math import floor

# --- ORIGINAL ---
rules = {
    'X': {
        1: 'FXFF+',
        2: '+XXF]',
    }
}

def next_char(c):
    isrule = rules.get(c, c)
    if not isrule == c:
        _, _choice = choice(list(rules.get(c).items()))
        return _choice
    else:
        return isrule

# --- ORIGINAL END ---

def next_char2(c):
    if c not in rules:
        return c

    d = rules[c]
    r = floor(random() * len(d))  # was int(...) before
    # Rules start with key 1.
    # Random brings a float between 0 and 1, therefore you need [r + 1] as key
    return d[r + 1]

choices=['FXFF+', '+XXF]']
def next_substring(s, n):
    if s == '' or n == 0:
        return s

    first_char = s[:1]
    rest = s[1:]

    if first_char == 'X':
        first_char = choice(choices)

    if len(first_char) == 1:
        return first_char + (next_substring(rest, n) if 'X' in rest else rest)
    else:
        return (next_substring(first_char, n-1) if 'X' in first_char else first_char) + (next_substring(rest, n) if 'X' in rest else rest)

format_rules = {
    'X': lambda: choice(["{F}{X}{F}{F}+", "+{X}{X}{F}]"]),
    'F': lambda: 'F',
    'J': lambda: 'J',
}

def format_based():
    def get_callbacks():
        while True:
            yield {k: v() for k, v in format_rules.items()}
    callbacks = get_callbacks()
    L_string = "{F}{X}"
    for _ in range(6):
        L_string = L_string.format(**next(callbacks))
    return re.sub(r'{|}', '', L_string)


def method1():
    s = 0
    for i in range(100_000):
        L_string = 'FX'
        for _ in range(6):
            L_string = ''.join([next_char(c) for c in L_string])
        s += len(L_string)
    return s

def method1b():
    s = 0
    for i in range(100_000):
        L_string = 'FX'
        for _ in range(6):
            L_string = ''.join([next_char2(c) for c in L_string])
        s += len(L_string)
    return s


def method2():
    s = 0
    for i in range(100_000):
        L_string = 'FX'
        L_string = ''.join(next_substring(c, 6) if c=='X' else c for c in L_string)
        s += len(L_string)
    return s

def method3():
    s = 0
    for i in range(100_000):
        L_string = format_based()
        s += len(L_string)
    return s

rules2 = [
    ('FXFF+', '+XXF]')      # X=0
]

def new_method2(s='FX'):
    final = [s]
    s = ''
    for _ in range(6):
        for c in final[-1]:
            if c == 'X':
                s += rules2[0][floor(random() * len(rules2[0]))]    # rules2[0] because X=0
            else:
                s += c
        final.append(s)
        s = ''
    return final[-1]

def method4():
    s = 0
    for i in range(100_000):
        L_string = new_method2('FX')
        s += len(L_string)
    return s

print('Average length of result string (100_000 runs):')
print('{: <20}{: >20}'.format('Original:', method1() / 100_000))
print('{: <20}{: >20}'.format('New method:', method2() / 100_000 ))
print('{: <20}{: >20}'.format('@hilberts method:', method3() / 100_000 ))
print('{: <20}{: >20}'.format('new_method2 method:', method4() / 100_000 ))
print('{: <20}{: >20}'.format('altunyurt method:', method1b() / 100_000 ))

print('{: <20}{: >20}'.format('Timing original:', timeit(lambda: method1(), number=1)))
print('{: <20}{: >20}'.format('Timing new method:', timeit(lambda: method2(), number=1)))
print('{: <20}{: >20}'.format('Timing @hilberts method:', timeit(lambda: method3(), number=1)))
print('{: <20}{: >20}'.format('new_method2 method:', timeit(lambda: method4(), number=1)))
print('{: <20}{: >20}'.format('altunyurt method:', timeit(lambda: method1b(), number=1)))

结果:

Average length of result string (100_000 runs):
Original:                       85.17692
New method:                     85.29112
@hilberts method:               85.20096
new_method2 method:             84.88892
altunyurt method:               85.07668
Timing original:       4.563865200005239
Timing new method:    2.6940059370026574
Timing @hilberts method:  1.9866539289942011
new_method2 method:   1.3680451929976698
altunyurt method:     1.7981422250013566

编辑:添加了@hilberts方法

EDIT2:添加了另一种新方法,比原始方法快约3.32倍

EDIT3:添加了@altunyurt方法

答案 3 :(得分:0)

您可以尝试使用具有替换值的re.sub作为根据您的情况生成随机规则的函数。您可以将字符串写入磁盘中的文件,然后 set buffering读取文件,然后将替换值写入另一个文件,然后重命名该文件并删除旧文件。希望这会有所帮助:)。

import re
import random
rules = {
    'X': ['FXFF+','+XXF]'],
    "Y" : ['A','B']
}

L_string = 'FX'

def next_char(c):
    return random.choice(rules[c.group()])

for _ in range(6):
    L_string = re.sub('|'.join(rules.keys()),next_char,L_string)
    print(L_string)

输出

FFXFF+
FFFXFF+FF+
FFF+XXF]FF+FF+
FFF++XXF]+XXF]F]FF+FF+
FFF+++XXF]FXFF+F]+FXFF+FXFF+F]F]FF+FF+
FFF++++XXF]FXFF+F]FFXFF+FF+F]+F+XXF]FF+F+XXF]FF+F]F]FF+FF+

已编辑

我进行了编辑,以使其速度更快并通过递归调用生成最后一个字符串。请原谅我使用全局变量:P。

import re
import random
rules = {
    'X': ['XX','XY'],
    'Y' : ['A', 'B']
}

L_string = 'FXY'
depth = 6
result = ''
index = 0 

def go(d,currentstring) :
    global result,depth
    if (d < depth):
        for c in currentstring:
            if c in rules:
                go(d + 1,random.choice(rules[c])) 
            else:
                result += c
    else:
        result += currentstring
go(0,L_string)
print(result)

答案 4 :(得分:0)

这将生成无替换的输出:

document.getElementsByTagName('body')[0].onclick = function(e) {console.log(e.target.id)};