什么是对列表中数字的增加数字进行排序/过滤/求和的最快方法

时间:2018-03-12 22:06:23

标签: python algorithm list sorting

示例:

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)

2:

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

任何帮助都将不胜感激。

4 个答案:

答案 0 :(得分:4)

OlivierMelançon解决方案非常优雅。但是,如果您愿意编写有点丑陋的代码,可以通过避免字符串转换并立即执行两个测试来使其运行得更快。我将你的解决方案ast1,OlivierMelanç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)

答案 1 :(得分:0)

如果您正在尝试使用功能方法,即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]

答案 2 :(得分:0)

依靠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]

答案 3 :(得分:0)

这是我不喜欢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将更多的计算工作卸载到快速工作的低级库中。在这种情况下,它可以使用矢量化数学运算来快速对整个输入执行数字检查。然后,您可以将它们用作过滤器。