P116: Drop every N'th element from a list
从列表中每隔N次去掉一个元素。比如,给定列表[a, b, c, d, e, f, g, h, i]
和N3
,则应去掉元素c, f, i
,剩下列表[a, b, d, e, g, h]
。照例还是先写测试用例:
from python99.lists.p116 import drop
def test_drop():
assert drop([1,2,3,4,5,6],2) == [1,3,5]
assert drop([1,2,3,4,5,6], 3) == [1,2,4,5]
assert drop([1,2,3,4,5,6], 4) == [1,2,3,5,6]
这个问题可以分三步解。首先,将列表中的每一个元素都转换为位置索引/元素元组(Tuple)。然后,按索引过泸元组。最后,把剩余元组的元素手日人取出来,拼成列表即为所求解。
套用MapReduce范式,Map(对映)先将元素转换为索引/元素元组,再把索引能被N整除的元组转换为空。**Reduce(归纳)则是把剩余元组内的元素提取出并拼接成列表。
Python内建了函数enumerate
可用以实现对映的第一步「将元素转换为索引/元素元组。比如,enumerate([a, b, c])
返回[(0, a), (1, b), (2, c)]
。
对映的第二步「把索引能被N整除的元组转换为空」可借由List comprehension的if子句实现。带if子句的List comprehension形式为:
[f(x) for x in l if condition]
f
为对映函数,可为普通Python函数,也可为表达式x
为局部变量,用以引用每一个元素l
输入列表condition
boolean
类型的表达式
本例中,x
为二元组,f
祇取二元组中的元素,condition
则判断二元组中的索引加一(list
索引是从零开始的)是否可被N整除
完整的代码实现:
# Drop every N'th element from a list
def drop(l, n):
return [e for i, e in enumerate(l) if (i+1) % n != 0]