凌晨两点还在改bug,已婚同事突然发消息:“老公送宵夜来了,分你一半不?那一瞬间,我破防了
刚看到个贴子,说凌晨两点改bug,已婚同事突然发消息:“老公送宵夜来了,分你一半不?”那一瞬间他直接破防。
我作为程序员真是共情了,这种场景就像你卡在一个死循环里,好不容易以为找到出口,结果别人已经下班在家开着空调看剧。
网友有人调侃“努力点,早日让别人破防”,也有人说“羡慕不如行动”。 我觉得吧,程序员的bug不只是代码里的,生活里的bug也不少。我们在职场拼命修复系统,却常常忘了修复自己的状态。深夜赶需求是常态,但如果一直这样,连吃宵夜的力气都没了,那生活质量就像无优化的SQL——慢到崩溃。 说到底,工作和生活都得有版本更新,别等到人生404才想回滚。【备注:文末可领最新资料】
面试题:锯齿迭代器
你想象一下,桌上有好几排小糖果,每一排的数量还不一样,比如第一排 3 颗,第二排 5 颗,第三排 2 颗。正常情况下,你要全吃完,可能会一排一排来,但锯齿迭代器不是这么玩的,它是轮着吃:先从第一排拿一个,再去第二排拿一个,再第三排…拿完最后一排又回到第一排,直到所有糖果都吃光。
说白了,这玩意的任务,就是在多行不等长数据里,按“来回轮流”方式遍历,不会一口气吃完一行才换行。
我上次写一个合并多数据源的接口,不同源的数据量不一样,直接拼接会让前面的数据全刷完,后面的才开始。但需求是让它们混着来,就像洗牌一样交错输出。这种就特别适合用锯齿迭代器。
比如数据长这样:
lists = [
[1, 2, 3],
[4, 5],
[6, 7, 8, 9]
]
目标结果:
1, 4, 6, 2, 5, 7, 3, 8, 9
最直接的写法
最笨也是最直观的,就是维护一个队列,把每个子列表变成迭代器,然后轮着取:
from collections import deque
classZigzagIterator:
def__init__(self, lists):
# 把非空的列表转换成迭代器,丢到队列里
self.queue = deque(iter(lst) for lst in lists if lst)
def__iter__(self):
return self
def__next__(self):
ifnot self.queue:
raise StopIteration
it = self.queue.popleft()
try:
val = next(it)
self.queue.append(it) # 还有数据的话放回去
return val
except StopIteration:
return self.__next__() # 当前空了,直接递归取下一个
使用:
it = ZigzagIterator(lists)
print(list(it))
# 输出: [1, 4, 6, 2, 5, 7, 3, 8, 9]
这种写法思路简单:队列控制“轮着来”,谁没数据了直接踢掉。
稍微优雅一点的方式
如果你对 itertools 熟,cycle 和 islice 这种东西可以帮忙,但它的缺点是要额外判断空迭代器,否则会死循环。所以一般还是用上面那种手动队列更稳。
性能上有没有坑
其实数据量小的时候随便写都行,但要注意两个点:
如果数据量特别大,用生成器代替列表存储,可以避免一次性占用太多内存。 每次 pop/append 是 O(1) 操作,队列很适合这个场景,比普通 list 要高效。
现实里我用过的变种
有一次我不是轮着取一个,而是轮着取 N 个,比如第一轮从每个源取 2 条,下一轮再取 2 条,这种稍微改一下逻辑就行了,在 __next__ 那里控制“取几次再换下一个”。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领