在 Python 中跟踪重复列表中的值变化
Track value changes in a repetitive list in Python
我有一个包含重复值的列表,如下所示:
x = [1, 1, 1, 2, 2, 2, 1, 1, 1]
此列表是根据模式匹配正则表达式(此处未显示)生成的。该列表保证具有重复值(很多很多重复 - 数百,如果不是数千),并且永远不会随机排列,因为这就是正则表达式每次匹配的内容。
我想要的是跟踪条目从先前值发生变化的列表索引。因此,对于上面的列表 x
,我想获得一个更改跟踪列表 [3, 6]
,表明 x[3]
和 x[6]
与它们之前在列表中的条目不同。
我设法做到了,但我想知道是否有更简洁的方法。这是我的代码:
x = [1, 1, 1, 2, 2, 2, 1, 1, 1]
flag = []
for index, item in enumerate(x):
if index != 0:
if x[index] != x[index-1]:
flag.append(index)
print flag
输出:[3, 6]
问题:有没有一种更简洁的方法可以用更少的代码行来完成我想做的事情?
可以使用列表理解来完成,使用 range
函数
>>> x = [1, 1, 1, 2, 2, 2, 3, 3, 3]
>>> [i for i in range(1,len(x)) if x[i]!=x[i-1] ]
[3, 6]
>>> x = [1, 1, 1, 2, 2, 2, 1, 1, 1]
>>> [i for i in range(1,len(x)) if x[i]!=x[i-1] ]
[3, 6]
而不是具有 O(n)
复杂性的多索引,您可以使用迭代器来检查列表中的下一个元素:
>>> x =[1, 1, 1, 2, 2, 2, 3, 3, 3]
>>> i_x=iter(x[1:])
>>> [i for i,j in enumerate(x[:-1],1) if j!=next(i_x)]
[3, 6]
我在这里添加包含列表理解的强制性答案。
flag = [i+1 for i, value in enumerate(x[1:]) if (x[i] != value)]
你可以使用 itertools.izip
, itertools.tee
和列表理解来做这样的事情:
from itertools import izip, tee
it1, it2 = tee(x)
next(it2)
print [i for i, (a, b) in enumerate(izip(it1, it2), 1) if a != b]
# [3, 6]
使用 itertools.groupby
on enumerate(x)
的另一种选择。 groupby
将相似的项目组合在一起,所以我们只需要除第一个之外的每个组的第一个项目的索引:
from itertools import groupby
from operator import itemgetter
it = (next(g)[0] for k, g in groupby(enumerate(x), itemgetter(1)))
next(it) # drop the first group
print list(it)
# [3, 6]
如果 NumPy 是一个选项:
>>> import numpy as np
>>> np.where(np.diff(x) != 0)[0] + 1
array([3, 6])
itertools.izip_longest
就是你要找的:
from itertools import islice, izip_longest
flag = []
leader, trailer = islice(iter(x), 1), iter(x)
for i, (current, previous) in enumerate(izip_longest(leader, trailer)):
# Skip comparing the last entry to nothing
# If None is a valid value use a different sentinel for izip_longest
if leader is None:
continue
if current != previous:
flag.append(i)
我有一个包含重复值的列表,如下所示:
x = [1, 1, 1, 2, 2, 2, 1, 1, 1]
此列表是根据模式匹配正则表达式(此处未显示)生成的。该列表保证具有重复值(很多很多重复 - 数百,如果不是数千),并且永远不会随机排列,因为这就是正则表达式每次匹配的内容。
我想要的是跟踪条目从先前值发生变化的列表索引。因此,对于上面的列表 x
,我想获得一个更改跟踪列表 [3, 6]
,表明 x[3]
和 x[6]
与它们之前在列表中的条目不同。
我设法做到了,但我想知道是否有更简洁的方法。这是我的代码:
x = [1, 1, 1, 2, 2, 2, 1, 1, 1]
flag = []
for index, item in enumerate(x):
if index != 0:
if x[index] != x[index-1]:
flag.append(index)
print flag
输出:[3, 6]
问题:有没有一种更简洁的方法可以用更少的代码行来完成我想做的事情?
可以使用列表理解来完成,使用 range
函数
>>> x = [1, 1, 1, 2, 2, 2, 3, 3, 3]
>>> [i for i in range(1,len(x)) if x[i]!=x[i-1] ]
[3, 6]
>>> x = [1, 1, 1, 2, 2, 2, 1, 1, 1]
>>> [i for i in range(1,len(x)) if x[i]!=x[i-1] ]
[3, 6]
而不是具有 O(n)
复杂性的多索引,您可以使用迭代器来检查列表中的下一个元素:
>>> x =[1, 1, 1, 2, 2, 2, 3, 3, 3]
>>> i_x=iter(x[1:])
>>> [i for i,j in enumerate(x[:-1],1) if j!=next(i_x)]
[3, 6]
我在这里添加包含列表理解的强制性答案。
flag = [i+1 for i, value in enumerate(x[1:]) if (x[i] != value)]
你可以使用 itertools.izip
, itertools.tee
和列表理解来做这样的事情:
from itertools import izip, tee
it1, it2 = tee(x)
next(it2)
print [i for i, (a, b) in enumerate(izip(it1, it2), 1) if a != b]
# [3, 6]
使用 itertools.groupby
on enumerate(x)
的另一种选择。 groupby
将相似的项目组合在一起,所以我们只需要除第一个之外的每个组的第一个项目的索引:
from itertools import groupby
from operator import itemgetter
it = (next(g)[0] for k, g in groupby(enumerate(x), itemgetter(1)))
next(it) # drop the first group
print list(it)
# [3, 6]
如果 NumPy 是一个选项:
>>> import numpy as np
>>> np.where(np.diff(x) != 0)[0] + 1
array([3, 6])
itertools.izip_longest
就是你要找的:
from itertools import islice, izip_longest
flag = []
leader, trailer = islice(iter(x), 1), iter(x)
for i, (current, previous) in enumerate(izip_longest(leader, trailer)):
# Skip comparing the last entry to nothing
# If None is a valid value use a different sentinel for izip_longest
if leader is None:
continue
if current != previous:
flag.append(i)