我有一个如下所示的列表:
a=[1,2,3,4,5,2,3,1,2,3,4,5,1,5,5,3,2,1,3,1]
我正在寻找一种方法,每次找到1时,此元素和接下来的两个元素都被-999替换。以下代码似乎有效。
b = a
x = 2 #number of continuous elements to browse
for n,i in enumerate(a):
if i==1:
for t in range(x):
print n+t
b[n+t]=-999
print b
然而,当1位于列表的末尾时,我得到:
IndexError:列表分配索引超出范围
有更好的方法吗?
答案 0 :(得分:2)
这是一种特殊情况 - 对于列表末尾的元素,下一个元素不存在。在访问列表之前,您需要在内部循环中检查此特殊情况:
if n+t >= len(b):
break
答案 1 :(得分:2)
单行:
b = [(i, -999)[1 in a[max(0,n-x):n+1]] for n, i in enumerate(a)]
产地:
# x = 2
[-999, -999, -999, 4, 5, 2, 3, -999, -999, -999, 4, 5, -999, -999, -999, 3, 2, -999, -999, -999]
# x = 1
[-999, -999, 3, 4, 5, 2, 3, -999, -999, 3, 4, 5, -999, -999, 5, 3, 2, -999, -999, -999]
(i, -999)[1 in a[max(0,n-x):n+1]]
转换为:如果可以在此-999
索引中找到1,请选择x
,否则请自行i
。
答案 2 :(得分:1)
我的方法是使用变量seen
,其值在0,1,2之间循环:
def replace_element_and_next(seq, search, replace):
seen = 0
for x in seq:
if x == search:
yield replace
seen = 1
elif seen in [1, 2]:
yield replace
seen = (seen + 1) % 3
else:
yield x
a = [1, 2, 3, 4, 5, 2, 3, 1, 2, 3, 4, 5, 1, 5, 5, 3, 2, 1, 3, 1]
print(','.join('%4d' % x for x in a))
b = replace_element_and_next(a, 1, -999)
print(','.join('%4d' % x for x in b))
输出:
1, 2, 3, 4, 5, 2, 3, 1, 2, 3, 4, 5, 1, 5, 5, 3, 2, 1, 3, 1
-999,-999,-999, 4, 5, 2, 3,-999,-999,-999, 4, 5,-999,-999,-999, 3, 2,-999,-999,-999
seen
初始化为0 seen
(0,1,2)的值表示我看过搜索字词0,1或2次 seen = (seen + 1) % 3
确保seen
的值在0,1和2的范围内函数replace_element_and_next()
返回一个生成器对象。如果您需要列表,请执行以下操作:
b = list(replace_element_and_next(a, 1, -999))
答案 3 :(得分:0)
较短的方法是使用itertools.groupby
:
import itertools
a=[1,2,3,4,5,2,3,1,2,3,4,5,1,5,5,3,2,1,3,1]
new_a = [(a, list(b)) for a, b in itertools.groupby(a, key=lambda x:x == 1)]
final_a = list(itertools.chain(*[[-999] if a else [-999, -999, *b[2:]] for a, b in new_a]))
输出:
[-999, -999, -999, 4, 5, 2, 3, -999, -999, -999, 4, 5, -999, -999, -999, 3, 2, -999, -999, -999, -999]
编辑:Python2的解决方案:
import itertools
a=[1,2,3,4,5,2,3,1,2,3,4,5,1,5,5,3,2,1,3,1]
new_a = [(a, list(b)) for a, b in itertools.groupby(a, key=lambda x:x == 1)]
final_a = list(itertools.chain(*[[-999] if a else [-999, -999]+b[2:] for a, b in new_a]))
答案 4 :(得分:0)
你可以检查你想要编辑的元素的索引,或者我确定python成语是求助宽恕比要求许可更好。你可以在它周围包装一个try语句,并在发生特定错误时传递。
b = a
x = 2 #number of continuous elements to browse
for n,i in enumerate(a):
if i==1:
for t in range(x):
print n+t
try: b[n+t]=-999
except IndexError:
# either pass or append right?
b.append(-999)
# pass
print b
但是,建议的那个突破会为你节省一些。
答案 5 :(得分:0)
由于你没有描述所有的情况,比如最后有两个1然后你想忽略它或者想要添加它,因为那个1是单个的,而且没有其他的下两个元素,
但是你评论说:
我也感兴趣的是' 1'值变为-999所以输出 看起来像[-999,-999,-999,4,5,2,3,-999,-999,-999,4,5,1, -999,-999,3,2,-999,-999,-999,-999]
所以:
这是一种非常简单的方法,不会使其变得复杂或导入任何模块:
a=[1,2,3,4,5,2,3,1,2,3,4,5,1,5,5,3,2,1,3,1,1]
for i,j in enumerate(a):
try:
if j == 1:
a[i] = -999
a[i + 1] = -999
a[i + 2] = -999
except IndexError:
pass
print(a)
输出:
[-999, -999, -999, 4, 5, 2, 3, -999, -999, -999, 4, 5, -999, -999, -999, 3, 2, -999, -999, -999, -999]
答案 6 :(得分:0)
添加到已经给出的其他答案,一个简单的方法是在indices
中创建必须替换1
的所有位置的集合a
,然后过滤该集合确保没有索引无效,例如当列表大小仅为a[21]
时访问20
。这是为了确保没有索引超出a
的长度,这将导致IndexError: list assignment index out of range
错误。
最后,您只需从此套装中替换a
中找到的每个位置即可。
以下是我的看法:
a=[1,2,3,4,5,2,3,1,2,3,4,5,1,5,5,3,2,1,3,1]
indices = set()
for i, e in enumerate(a):
if e == 1:
indices.add(i)
indices.add(i+1)
indices.add(i+2)
pos = {x for x in indices if x < len(a)}
for i in pos:
a[i] = -999
print(a)
哪个输出:
[-999, -999, -999, 4, 5, 2, 3, -999, -999, -999, 4, 5, -999, -999, -999, 3, 2, -999, -999, -999]
注意:与大多数其他答案一样,上述时间复杂度为O(N)
。我还使用集合代替列表来存储索引,因为您可以没有重复项。
答案 7 :(得分:0)
使用range()
和len()
,您可以尝试:
a = [1,2,3,4,5,2,3,1,2,3,4,5,1,5,5,3,2,1,3,1]
for i in range(len(a)):
if a[i] == 1:
if len(a) - i >= 2:
a[i] = -999
a[i+1] = -999
a[i+2] = -999
print(a)
[-999, -999, -999, 4, 5, 2, 3, -999, -999, -999, 4, 5, -999, -999, -999, 3, 2, -999, -999, -999]
>>>