【问题标题】:what's the fastest way to sort/filter/sum increasing digits of numbers in a list什么是排序/过滤/求和列表中增加数字的最快方法
【发布时间】:2018-03-12 22:06:23
【问题描述】:

示例:

L = [12,14,22,41,21,23]

我希望结果是:

R == [12,14,22,23]

数字的数字必须按递增顺序排列,以下是我的解决方案,它们都可以工作,但是它们都太慢了。

最快的排序方法是什么?

解决方案一:

R = filter(lambda j: int(''.join(sorted(str(j))))==j , L)

解决方案二:

for j in L:
      if int(''.join(sorted(str(j))))==j:
          R.append(j)

问题 2 - 另外,我希望将这些对应数字相加的总和等于 5。

这是我的解决方案,同样,它们确实有效,但速度太慢。

那么最快的方法是什么。

newR_should_be == [14,23]

一个:

newR = filter(lambda i: sum([int(x) for x in str(i)])==5 ,R)

两个:

for i in R:
         if sum([int(x) for x in str(i)])==5:
             newR.append(i)

任何帮助将不胜感激。

【问题讨论】:

  • 所有数字都只有两位数吗?
  • 不一定,但数字总是相同的数字,要么全是两位数,要么全是三位数,或者 [4123,4223,4567] 等等......
  • 如果您真正想做的是在某个范围内计算或枚举具有该属性的数字,那么有比生成所有有效数字并计算它们更快的解决方案。

标签: python algorithm list sorting


【解决方案1】:

Olivier Melançon 的解决方案非常优雅。但是,如果您愿意编写更难看的代码,则可以通过避免字符串转换并同时进行两个测试来使其运行得更快一些。我实现了你的解决方案 ast1,Olivier Melançon 为 t2,我的为 t3。

def FastFilter(n):
    x = n % 10
    s = x
    n //= 10
    while n:
        y = n % 10
        s += y
        if (x < y):
            return False
        x = y;
        n //= 10
    return s==5

def sort_by_digits(l):
    return sorted(set(int(''.join(sorted(str(x)))) for x in l))

def filter_by_sum(l, total=5):
    return [x for x in map(str, l) if sum(map(int, x)) == total]

def t1(L):
    R = filter(lambda j: int(''.join(sorted(str(j))))==j , L)
    newR = filter(lambda i: sum([int(x) for x in str(i)])==5 ,R)
    return sorted(newR)

def t2(l):
    return sort_by_digits(filter_by_sum(l))

def t3(l):
    return sorted(filter(FastFilter, l))

l = [12, 14, 22, 41, 21, 23]

%timeit t1(l)
%timeit t2(l)
%timeit t3(l)

给予

11.2 µs ± 24.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
8.88 µs ± 24.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
2.71 µs ± 12.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

【讨论】:

  • 非常好的答案!我有兴趣在更多数字的更大列表上查看时间。
  • 对其他答案进行基准测试真的很有趣。谢谢!
  • 如果 L 包含任意位数的数字怎么办
  • @englealuze 我写的 FastFilter 过滤函数可以处理任意位数的数字。总和的价值确实需要增加才能让它变得有趣。只有六个数字(5、14、23、122、1112、11111)满足原问题的性质。
【解决方案2】:

如果您正在尝试功能性方法,即filter,您可以试试这个:

L = [12,14,22,41,21,23]
while not all(L[i] <= L[i+1] for i in range(len(L)-1)):
  L = map(lambda x:x[-1], filter(lambda x:L[x[0]+1] >= x[-1] if x[0]+1 < len(L) else True, zip(range(len(L)), L)))

print(L)

输出:

[12, 14, 21, 23]

【讨论】:

    【解决方案3】:

    依赖 Python 内置通常是最有效的方法。它还允许只用几行代码做很多事情。

    l = [12, 14, 22, 41, 21, 23]
    
    def sort_by_digits(l):
        return sorted(set(int(''.join(sorted(str(x)))) for x in l))
    
    sort_by_digits(l) # [12, 14, 21, 23]
    

    至于总和,你可以做类似的事情。

    def filter_by_sum(l, total=5):
        return [x for x in map(str, l) if sum(map(int, x)) == total]
    
    sort_by_digits(filter_by_sum(l)) # [14, 23]
    

    【讨论】:

      【解决方案4】:

      这是我不喜欢 Python 的原因之一:您提出的简单解决方案在大多数语言中都可以很好地工作,但在 Python 中可能和糖蜜一样慢。高级操作过多。

      但是我们可以通过使用 Numpy 来解决这个问题,如下所示:

      #!/usr/bin/env python3
      
      import numpy as np
      
      COUNT      = 1000
      MAXNUM     = 100000
      MAXDIGITS  = 6
      prevremain = 99*np.ones(COUNT)                        #The previous digit we removed from the RHS
      origdata   = np.random.randint(0,MAXNUM,size=COUNT)   #Original data
      quot       = origdata.copy()                          #What's left when we remove a digit from the RHS
      good       = np.ones(COUNT)                           #Whether the number's digits are monotonically decreasing from right to left
      
      for i in range(1,MAXDIGITS):                          #Pull digits off of the numbers one at a time
        quot, remain = np.divmod(quot,10)                   #quot is the rest of the number, remain is the right-most digit
        #Check to see if this digit was smaller, or equal to, than the last one we
        #removed. NOTE: If you have numbers with an unequal number of digits, you'll
        #need to think carefully about whether `<=` might work better for you.
        good         = np.logical_and(good, (remain < prevremain))
        prevremain   = remain
      
      #These are the numbers you want
      print(origdata[good])
      

      Numpy 将更多的计算卸载到运行速度很快的低级库。在这种情况下,它可以使用矢量化数学运算对整个输入快速执行数字检查。然后,您可以将它们用作过滤器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-05
        • 2014-02-25
        • 1970-01-01
        • 2015-02-27
        • 2018-05-22
        • 1970-01-01
        相关资源
        最近更新 更多