Python中如何高效排除range中的指定间隔数?
无大列表的范围数字过滤高效实现
针对你提出的三个场景,这里给出无需创建大型列表、内存友好的高效方案:
1. 从range中排除每第n个数字(例:1-100排除第3个)
如果是排除位置上的第n个、第2n个...(比如1-100里的第3、6、9位数字),用生成器跟踪位置即可;如果是排除数值为n的倍数,推荐用拼接range的方式,完全惰性求值,无额外内存消耗:
方案一:生成器(灵活通用)
def exclude_every_nth(start, end, n): for idx, num in enumerate(range(start, end+1), start=1): if idx % n != 0: yield num # 调用示例:1-100排除每第3个数字 for num in exclude_every_nth(1, 100, 3): print(num)
如果要排除数值本身是n的倍数,把判断条件改成num % n != 0即可。
方案二:拼接range(超大范围更高效)
利用range的惰性特性,直接生成连续的有效区间,完全不需要循环判断:
def exclude_multiples(start, end, n): # 处理开头的不完整块 first_block_end = min(start + n - 1, end) yield from range(start, first_block_end + 1) # 循环生成后续的完整块(每个块跳过一个n的倍数) current = first_block_end + 1 while current <= end: block_end = min(current + n - 1, end) yield from range(current, block_end + 1) current += n # 调用示例:1-100排除3的倍数 for num in exclude_multiples(1, 100, 3): print(num)
2. 排除多个间隔数(例:同时排除第3和第11个)
本质是排除多个数的倍数,分两种场景选择方案:
方案一:生成器+多条件判断(简单直观,适合少量倍数)
def exclude_multi_multiples(start, end, multiples): for num in range(start, end+1): # 仅保留不被任何指定倍数整除的数 if not any(num % m == 0 for m in multiples): yield num # 调用示例:1-100排除3和11的倍数 for num in exclude_multi_multiples(1, 100, [3, 11]): print(num)
方案二:容斥原理拼接range(超大范围高效)
如果范围极大,不想做任何取模运算,用容斥原理生成所有有效区间(以两个倍数为例,多倍数可扩展逻辑):
import math import itertools def exclude_multiples_large_range(start, end, multiples): m1, m2 = multiples lcm = m1 * m2 // math.gcd(m1, m2) # 最小公倍数 template = [x for x in range(1, lcm+1) if x % m1 != 0 and x % m2 != 0] # 计算第一个周期的起始点 start_cycle = ((start - 1) // lcm) * lcm + 1 current = start_cycle while current <= end: offset = current - 1 for num in template: val = offset + num if val > end: break if val >= start: yield val current += lcm # 调用示例:1-1000000排除3和11的倍数 for num in exclude_multiples_large_range(1, 10**6, [3, 11]): pass
3. 超大范围排除能被3整除的数(替代取模的高效方案)
最极致的高效方式是直接拼接连续的有效range,完全没有取模运算,内存占用为O(1):
import itertools def exclude_divisible_by_3(start, end): ranges = [] # 处理开头的不完整块 first_excluded = ((start + 2) // 3) * 3 if start < first_excluded: ranges.append(range(start, first_excluded)) # 生成中间的完整块(每个块包含2个连续数,跳过1个3的倍数) current = first_excluded while current + 2 <= end: ranges.append(range(current + 1, current + 3)) current += 3 # 处理结尾的不完整块 if current + 1 <= end: ranges.append(range(current + 1, end + 1)) # 拼接所有range并返回 yield from itertools.chain(*ranges) # 调用示例:1到1亿的范围内排除3的倍数 for num in exclude_divisible_by_3(1, 10**8): # 处理每个数,无内存压力 pass
这个方案利用range的底层优化,所有操作都是数学计算,效率远高于逐个取模。
内容的提问来源于stack exchange,提问作者Jonas David
相关产品推荐
相关产品推荐

