【问题标题】:Simplify an "if" condition简化“如果”条件
【发布时间】:2020-02-12 12:57:16
【问题描述】:

Soo...我正在尝试解决问题 n。 8 在 Project Euler 的网站 (https://projecteuler.info/problem=8) 我想知道是否有一种更简洁的方式来写这个 if 条件

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: 在我编辑的时候你回答了,谢谢大家!

【问题讨论】:

  • 也不要使用Max作为变量名。

标签: python string list


【解决方案1】:

您可以使用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 倍以上。

【讨论】:

  • 第二种方法(您编辑的那个)由于字符串中的零而不起作用。具体来说,p = p * seq[i] // seq[i-k] 的结果是 ZeroDivisionError
【解决方案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])

【讨论】:

  • 对不起,@Alexander,它给出了正确的答案。我刚刚通过将代码复制到 python 控制台(python 3.5.2,numpy 1.17.2)进行检查,它给了我最大产品的编号23514624000。然后,我访问了(projecteuler.info/problem=8)并输入了这个号码,我收到了以下信息:恭喜,你对问题8的回答是正确的。
  • 确实如此。我很抱歉。我想我只是看了你的最终结果,它给出了序列而不是解决方案。
  • 没问题。我明白了,最终答案在文本结尾处更直观。刚刚制作并编辑以解决该问题。谢谢。
【解决方案3】:

直接使用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

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

【讨论】:

  • 这给出了提示,但实际上并没有回答问题。
  • @Alexander 感谢投票,但问题已经改变了很多次(我是第一个发帖者)——显然,它最初不得不单独使用 if 声明
【解决方案4】:

如果您询问如何简化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 数字,则第二种方法不起作用。处理它会大大复杂化。

【讨论】:

  • 是的,我已经更改了变量名
  • 我几乎删除了我的答案,认为它与你的基本相似。但是,您的第二种方法不起作用,因为当s[i] 为零时,您会得到一个ZeroDivisionError
【解决方案5】:

虽然不如@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)

【讨论】:

    【解决方案6】:

    您正在寻找的 if-condition-shortener 是 functools.reduceoperator.mul 和字符串切片的组合:

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

    别忘了import functoolsoperator

    【讨论】:

      猜你喜欢
      • 2020-06-11
      • 2022-12-08
      • 2020-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-17
      • 2021-05-03
      • 2012-06-03
      相关资源
      最近更新 更多