我们以列表为例:
a = [255, 255, 1, 255, 255, 255, 1, 2, 255, 255, 2, 255, 255, 3, 255, 3, 255, 255, 255]
255
是一个特殊值。这是一个占位符。
我做了一个生成器,它替换了列表中的一些占位符。它按预期工作。
但我不需要处理起始占位符[255, 255
和结束占位符255, 255, 255]
并完整地生成它们。
所以,我试图修改生成器来解决它:
Python 2.7
from __future__ import print_function
from itertools import tee, izip, ifilterfalse
def replace(iterable,placeholder=255):
it = enumerate(iterable) #the position is needed for the logic for the middle of the list
it = ifilterfalse(lambda x: x[1]==placeholder, it) #create an iterator that deletes all the placeholders
for i,(left,right) in enumerate(window(it,2)): #Slide through the filtered list with the window of 2 elements
if i==0: #Leaving the beginning placeholders intact
for j in range(left[0]):
yield placeholder
#SOME LOGIC FOR THE MIDDLE OF THE LIST (it works well)
#Need to leave the trailing placeholders intact.
转换为列表的临时值只是为了便于理解代码:
>>>iterable
[255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3,255,255]
>>>it = enumerate(iterable)
[(0, 255), (1, 1), (2, 255), (3, 255), (4, 1), (5, 255), (6, 255), (7, 255), (8, 2), (9, 2), (10, 255), (11, 255), (12, 255), (13, 2), (14, 2), (15, 3), (16, 255), (17, 255), (18, 255), (19, 3), (20, 255), (21, 255)]
>>>it = ifilterfalse(lambda x: x[1]==placeholder, it)
[(1, 1), (4, 1), (8, 2), (9, 2), (13, 2), (14, 2), (15, 3), (19, 3)]
>>>list(enumerate(window(it,2)))
[(0, ((1, 1), (4, 1))), (1, ((4, 1), (8, 2))), (2, ((8, 2), (9, 2))), (3, ((9, 2), (13, 2))), (4, ((13, 2), (14, 2))), (5, ((14, 2), (15, 3))), (6, ((15, 3), (19, 3)))]
因此,正如您所看到的,list(enumerate(window(it,2)))
包含前导非占位符值(0, ((**1**, 1), (4, 1))),
的索引,但它不包含初始迭代器具有多少尾随占位符的信息:{ {1}}以此值list(enumerate(window(it,2)))
结尾,该值仅包含最后一个非占位符值的索引,但不会提供剩余占位符的信息。
我设法依靠(6, ((15, 3), (**19**, 3)))
来处理主要占位符,它产生初始迭代器值的位置,该值在it = enumerate(iterable)
的第一个产生值中持续存在。
但是我花了很多时间试图弄清楚如何用尾随占位符做同样的事情。问题是ifilterfalse
只是吞下了ifilterfalse
的最后一个占位符值,我认为无法访问它们(由于enumerate(iterable)
的第一个生成值包含ifilterfalse
)的值的索引。
问题
更正此代码以处理尾随占位符的最佳方法是什么?
由于目标不是通过各种手段创建代码(我已经done it使用不同的技术),我想通过修改代码来解决任务,而不是完全重写它。
这更像是一场训练,而不是一项真正的任务。
其他信息
enumerate(iterable)
是来自here的代码。
我的代码与@ nye17的this回答几乎相同。但是在这段代码中,作者对初始列表进行了原位修改。我想创建一个生成器,它将产生与该代码中的结果列表相同的值。
此外,我希望我的生成器接受任何迭代作为参数,而不仅仅是列表(例如它可以接受迭代器逐个读取文件中的值)。只有列表作为参数,任务变得更简单,因为我们可以从最后扫描列表。
这不是我必须在生活中解决的真正任务。这只是为了训练。
答案 0 :(得分:2)
def replace(it, process, placeholder):
it = iter(it)
while True:
item = it.next()
if item == placeholder:
yield item
else:
yield process(item)
pcount = 0
try:
while True:
item = it.next()
if item == placeholder:
pcount += 1
else:
for i in range(pcount):
yield process(placeholder)
pcount = 0
yield process(item)
except StopIteration:
for i in range(pcount):
yield placeholder
像这样使用:
>>> a = [0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 3, 0, 3, 0, 0, 0]
>>> [x for x in replace(a, lambda n: n+20, 0)]
[0, 0, 21, 20, 20, 20, 21, 22, 20, 20, 22, 20, 20, 23, 20, 23, 0, 0, 0]
答案 1 :(得分:0)
def replace(it, placeholder):
while True:
curr = it.next()
if curr == placeholder:
yield curr
else:
break
yield curr
try:
cache = []
while True:
curr = it.next()
if curr == placeholder:
cache.append(curr)
else:
for cached in cache:
yield TRANSFORM(cached)
yield curr
cache = []
except StopIteration:
for cached in cache:
yield cache
答案 2 :(得分:0)
我提出的最简单的解决方案是通过另一个生成器处理it = enumerate(iterable)
,它只保存最后返回的值。
所以,我在it = enumerate(iterable)
之后添加了以下代码(在replace
函数内):
def save_last(iterable):
for i in iterable:
yield i
replace.last_index = i[0] #Save the last value
it = save_last(it)
iterable
耗尽后,生成器的最后一个运算符会保存已生成值的索引(i[0]
为enumerate
,0
将其存储在replace
的位置tupele)作为replace
属性(因为it
函数是一个类的实例,它可以有局部变量)。
save_last
包含在新创建的生成器replace.last_index
中。
在函数的最后,我添加了使用if right[0]<replace.last_index:
for i in range(replace.last_index-right[0]):
yield placeholder
变量中已保存索引的代码。
from __future__ import print_function
from itertools import tee, izip, ifilterfalse
def window(iterable,n):
els = tee(iterable,n)
for i,el in enumerate(els):
for _ in range(i):
next(el, None)
return izip(*els)
def replace(iterable,placeholder=255):
it = enumerate(iterable)
def save_last(iterable):
for i in iterable:
yield i
replace.last_index = i[0] #Save the last value
it = save_last(it)
it = ifilterfalse(lambda x: x[1]==placeholder, it)
for i,(left,right) in enumerate(window(it,2)):
if i==0:
for j in range(left[0]):
yield placeholder
yield left[1]
if right[0]>left[0]+1:
if left[1]==right[1]:
for _ in range(right[0]-left[0]-1):
yield left[1]
else:
for _ in range(right[0]-left[0]-1):
yield placeholder
yield right[1]
if right[0]<replace.last_index:
for i in range(replace.last_index-right[0]):
yield placeholder
a = [255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3,255,255]
print('\nInput: {}'.format(a))
output = list(replace(a))
print('Proram output: {}'.format(output))
print('Goal output : {}'.format([255,1,1,1,1,255,255,255,2,2,2,2,2,2,2,3,3,3,3,3,255,255]))
完整代码:
Input: [255, 1, 255, 255, 1, 255, 255, 255, 2, 2, 255, 255, 255, 2, 2, 3, 255, 255, 255, 3, 255, 255]
Proram output: [255, 1, 1, 1, 1, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 255, 255]
Goal output : [255, 1, 1, 1, 1, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 255, 255]
按预期工作:
ifilterfalse
我唯一不喜欢的是使用Python编写的C save_last
和{{1}}编写的非常高效的组合。