我想这样做:有一个数字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
答案 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 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