如何过滤出具有特定数字的数字?

时间:2019-05-10 20:50:44

标签: python

我想这样做:有一个数字N。有多少个数字小于N(仅包含0或4或7位数字)? 例如:N = 50,好的数字是:0,4,7,40,44,47。 total_count = 6

import Foundation

let s1 = "بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ"
let s2 = "بسم الله الرحمن الرحيم"

print(s1 == s2)
// false

print(s1.compare(s2, options: .diacriticInsensitive) == .orderedSame)
// true

5 个答案:

答案 0 :(得分:5)

您可以将sum与这样的生成器表达式一起使用:

sum(1 for i in range(n + 1) if all(d in '047' for d in str(i)))

这将返回:6

请注意,这包括数字44,您的预期输出没有。

答案 1 :(得分:2)

您的代码有一些问题。在这种情况下,手动或借助调试器(因为它集成在许多IDE中)总是有助于逐步完成它。让我们看看您的代码:

n = 50
db = 0
badnums = '1235689'
lsgood = []
for i in range(0, n + 1):
    szamok = [int(j) for j in str(i)]
    for i in szamok:
        if str(i) not in badnums:
            lsgood.append(i)
            db += 1
print(lsgood,db)

首先应该引起注意的是变量名i的重用。您不应该这样做,所以我们将变量j

重命名。
n = 50
db = 0
badnums = '1235689'
lsgood = []
for i in range(0, n + 1):
    szamok = [int(j) for j in str(i)]
    for j in szamok:
        if str(j) not in badnums:
            lsgood.append(?)
            db += 1
print(lsgood,db)

但是现在我们有了第一个有趣的错误。我们要在lsgood后面附加什么?您添加了内部i,该内部数字始终为一位。这意味着lsgood仅包含一位数字,这不是您想要的。因此,我们添加了i

n = 50
db = 0
badnums = '1235689'
lsgood = []
for i in range(0, n + 1):
    szamok = [int(j) for j in str(i)]
    for j in szamok:
        if str(j) not in badnums:
            lsgood.append(i)
            db += 1
print(lsgood,db)

现在我们得到以下输出:

[0, 4, 7, 10, 14, 17, 20, 24, 27, 30, 34, 37, 40, 40, 41, 42, 43, 44, 44, 45, 46, 47, 47, 48, 49, 50] 26

这些是很多方法。如果我们仔细观察,它将计算包含至少一个“ 047”的所有数字。那不是我们想要的。因此,我们开始研究它并发现else on for-loops的魔力。

n = 50
db = 0
badnums = '1235689'
lsgood = []
for i in range(0, n + 1):
    szamok = [int(j) for j in str(i)]
    for j in szamok:
        if str(j) in badnums:
            break # The number contains a bad digit, we don't want it
    else:
        lsgood.append(i) # All digits past the test, it only contains good digits
        db += 1
print(lsgood, db)

这给出了预期的输出:

[0, 4, 7, 40, 44, 47] 6

正如其他人所言,这可以大大缩短,但是我认为对于初学者来说,这是更容易理解的解决方案。

答案 2 :(得分:2)

如果n很大,则迭代小于n的所有数字可能不是最有效的方法(尽管我没有做任何计时;如果性能很重要,这样做是值得的)。相反,我们可以生成可能有效的数字(所有数字与n具有相同的位数,但仅使用0、4或7),然后消除无效的数字(大于{{ 1}})。

n

编辑:与其他答案之一相比,我做了几个快速计时:

from itertools import product

def n_good(n: int = 50, allowed_digits: str = "047") -> int:
    n_digits = len(str(n))
    possible_nums = [int("".join(num)) for num in product(set(allowed_digits + "0"), repeat=n_digits)]
    if "0" not in allowed_digits:
        possible_nums = [num for num in possible_nums if "0" not in str(num)]
    return sum(1 for num in possible_nums if num < n)

assert n_good(50) == 6 and n_good(50, "47") == 4
def n_good_range(n):
    return sum(1 for i in range(n + 1) if all(d in '047' for d in str(i)))

(在IPython中使用| n | 10_000 | 100_000 | 1_000_000 | | ------------ | ---------------- | ---------------- | ----------------- | | n_good | 138 µs ± 9.48 µs | 464 µs ± 44.3 µs | 1.28 ms ± 42.5 µs | | n_good_range | 9.05 ms ± 319 µs | 91.5 ms ± 4.4 ms | 942 ms ± 57.9 ms | 完成的计时)

EDIT2:基于@Jan的深刻见解,即使0不是允许的数字之一,我也修复了该功能。有时候这会使操作稍微慢一些,但是我发现%%timeit只用了1.7毫秒(而n_good(1_000_000, "47")则用了1.3毫秒)。

答案 3 :(得分:0)

您可以使用set来简化代码:

n = 50

lsgood = []
for i in range(n):
    if set(list(str(i))).issubset(list('047')):
        lsgood.append(i)

print(lsgood, len(lsgood))

# [0, 4, 7, 40, 44, 47] 6

答案 4 :(得分:0)

使用itertools.combinations_with_replacement的解决方案(仅适用于两位数)

此解决方案使用combinations_with_replacement模块中的itertools,因为我们正在寻找小于目标值n且可重复的数字的所有数字组合。由于combinations_with_replacement('ABC', 2)返回AA AB AC BB BC CC,并因此认为BA == AB,我们必须将所有数字添加到字符串的后面,以覆盖其他组合配对,即,我们使用{{ 1}},而不是内部的'047047'

此解决方案避免了循环遍历所有值,这对于较大的'047'可能更有效。相反,我们只有N python循环:

log10(n)

Python 3.8赋值表达式

使用Python 3.8 Assignment Expressions,我们可以避免对集合中的值求和,但要以赋值表达式为代价:

def good_digits(n, digs='047'):
    import itertools

    digs = digs + digs[-2::-1]
    l = len(str(n)) 
    s = set(int("".join(i)) for j in range(1,l+1) for i in itertools.combinations_with_replacement(digs, j)) 
    return sum(1 for i in s if i < n)

good_digits(50, '047') # 6

排列

如果您希望排列而不是与替换组合,例如排除“ 44”,请使用此解决方案进行排列:

def good_digits_38(n, digs='047'):
    import itertools

    digs = digs + digs[-2::-1]
    l = len(str(n)) 
    s = set(r for j in range(1,l+1) for i in itertools.combinations_with_replacement(digs, j) if (r:=int("".join(i))) < n) 
    return len(s)

good_digits_38(50, '047') # 6