如果满足条件,则替换列表中的元素和后续元素

时间:2017-12-28 15:53:32

标签: python loops

我有一个如下所示的列表:

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:列表分配索引超出范围

有更好的方法吗?

8 个答案:

答案 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]
>>>