简化“如果”条件

时间:2019-10-15 19:34:27

标签: python string list

S ...我正在尝试解决问题n。 Project Euler网站(https://projecteuler.info/problem=8中的8) 我想知道是否有一种更干净的方式来编写条件代码

n="7316717653..." # there are 1000 digits 
(https://projecteuler.info/problem=8)
Max=0
s=[int(s) for s in n]
for i in range(len(s)-3):
    if s[i]*s[i+1]*s[i+2]*s[i+2] > Max:
            Max=s[i]*s[i+1]*s[i+2]*s[i+3]
print(Max)

# In particular
if s[i]*s[i+1]*s[i+2]*s[i+2] > Max:
            Max=s[i]*s[i+1]*s[i+2]*s[i+3]

我该如何写得更好(我还必须写成     如果s [i] * s [i + 1] * s [i + 2] * s [i + 2] * s [i + 3] ... * s [i + 13] 因此,找到一种更好的方法会很不错。 预先谢谢你!

编辑: 我写的帖子非常糟糕...对不起。

我的意思是:

我可以写s [i] * s [i + 1] * s [i + 2] * s [i + 3] * s [i + 4] * s [i + 5] * s [i +6] * s [i + 7] * s [i + 8] * s [i + 9] * s [i + 10] * s [i + 11] * s [i + 12] * s [i + 13]>最大值:

或根据建议(更好,谢谢)

Max = max(Max,s [i] * s [i + 1] * s [i + 2] * s [i + 3] * s [i + 4] * s [i + 5] * s [i + 6] * s [i + 7] * s [i + 8] * s [i + 9] * s [i + 10] * s [i + 11] * s [i + 12] * s [ i + 13])

以更好的方式? 就像用自动方式做s [i + n] 13或任何时间一样。 对不起,我的英语不好。

编辑2: 您在我编辑时回答了,谢谢大家!

6 个答案:

答案 0 :(得分:2)

您可以使用functools.reduce来计算乘积:

from functools import reduce
from operator import mul

reduce(mul, [2, 3, 4])  # calculates 2 * 3 * 4
# 24

您的代码将按照问题末尾的要求乘以13位数字:

from functools import reduce
from operator import mul

n = "7316717653..." # there are 1000 digits 
s = [int(s) for s in n]

maxi = max(reduce(mul, s[i:i+13]) for i in range(len(s)-13))

print(maxi)

编辑

尽管紧凑写,但这并不是真正有效,特别是当数字序列相乘的长度变长时。

一个更有效的想法是在滑动窗口中以数字的形式查看我们的产品。当窗口向右移动一位时,乘积除以刚从左边得出的数字,然后乘以在右边输入的数字。

这样,无论序列的长度如何,我们只需要获取两个数字并在每个步骤上执行两次操作即可。

def findmax(seq, k=13):
    p = reduce(mul, seq[:k])
    maxi = p
    for i in range(k, len(seq)):
        p = p * seq[i] // seq[i-k]
        if p > maxi:
            maxi = p
    return maxi

一些粗略的时序表明,长度为2的序列的速度已经快了2倍以上,长度为13的速度快了5倍以上。

答案 1 :(得分:2)

您可以使用numpy python库解决此问题。与列表或字符串相比,它可以更有效地处理数字数据。

例如,您可以使用以下方法解决此问题:

import numpy as np
#n = "7316717653..." # there are 1000 digits
n = '7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'

n_as_nparray = np.array([int(character) for character in n])
every_thirteen_char = np.array([n_as_nparray[i:i+13] for i in range(len(n)-13)])

您将拥有一个包含shape = (987,13)的数组。

然后,您的最大产品将是:

>>> every_thirteen_char.prod(axis=1).max()
23514624000

然后使用以下命令找到序列

>>> every_thirteen_char[every_thirteen_char.prod(axis=1).argmax()]
array([5, 5, 7, 6, 6, 8, 9, 6, 6, 4, 8, 9, 5])

答案 2 :(得分:1)

只需直接使用max函数,无需使用if语句。

Max = max(Max, s[i]*s[i+1]*s[i+2]*s[i+3])

对于累积乘积,您可以诉诸numpy之类的库,该库具有矢量化(即really fast)函数cumprodprod。例如,

import numpy as np

>>> np.cumprod([1,2,3,4,5])
array([  1,   2,   6,  24, 120])

>>> np.prod([1,2,3,4,5])
120

当然,将虚拟[1,2,3,4,5]替换为相应切片(例如s)的s[:13]

答案 3 :(得分:1)

如果您要问如何简化s[i]*s[i+1]*s[i+2]*s[i+2],则可以将product函数与列表切片一起使用。我从What's the function like sum() but for multiplication? product()?

得到了定义
from functools import reduce # Valid in Python 2.6+, required in Python 3
import operator

def product(sequence):
    reduce(operator.mul, sequence, 1)

n="7316717653..." # there are 1000 digits 
(https://projecteuler.info/problem=8)
s=[int(s) for s in n]
highest = s[0]
for i in range(1, len(s)-3):
    highest = max(highest, product(s[i:i+4]))
print(highest)

但是,如果您正在寻找性能优化,那不是做到这一点的方法。这是O(n*m),其中m是要相乘的子序列的长度,但是您可以利用以下事实:在转到下一个切片时,将当前乘积除以过去,然后乘以您要添加的元素,以获得O(n)算法。

highest = product(s[0:4])
for i in range(len(s)-5):
    highest = max(highest, highest/s[i]*s[i+4]))
print(highest)

哎呀,如果有0位数字,则第二种方法不起作用。处理该问题会使其复杂化。

答案 4 :(得分:1)

尽管不如@Thierry提供的简单解决方案那么漂亮,但此解决方案的速度明显更快(约5倍)。因为包含零使乘积为零,所以我在此字符上拆分了文本。在使用reduce获得前13个字符的乘积后,我然后通过新数字与下降的乘数之比来更新此乘积。该产品始终根据全局最大值进行测试。

big_number = '7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'
n = 13
global_max = 0
for chunk in big_number.split('0'):
    if len(chunk) < n:
        continue
    product = reduce(lambda x, y: x * int(y), chunk[:n], 1)  # Product of first `n` integers in `chunk`.
    global_max = max(global_max, product)
    for i in range(n, len(chunk)):
        product *= (int(chunk[i]) / int(chunk[i - n]))  # Rolling product of window size `n`.
        if product > global_max:
            global_max = product
>>> int(global_max)
23514624000

时间

%%timeit -n 1000  # Code above.
# 437 µs ± 76.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%%timeit -n 1000
s = [int(s) for s in big_number]
maxi = max(reduce(mul, s[i:(i + 13)]) for i in range(len(s) - 13))
# 2.46 ms ± 916 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# Using numpy.
%%timeit -n 1000
n_as_nparray = np.array([int(character) for character in big_number])
every_thirteen_char = np.array([n_as_nparray[i:(i + 13)] for i in range(len(big_number) - 13)])
every_thirteen_char.prod(axis=1).max()
# 2.81 ms ± 418 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# Using pandas with a rolling window.
%%timeit -n 100
s = pd.Series([int(c) for c in big_number])
s.rolling(window=13, min_periods=1).apply(np.prod, raw=True).max().astype(int)
# 8.06 ms ± 830 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

答案 5 :(得分:0)

您要查找的if-condition-shortener是functools.reduceoperator.mul以及字符串切片的组合:

m = functools.reduce(operator.mul, s[i:i+13])
if m > Max:
    Max = m

别忘了import functoolsoperator