Python 2.7 优化python代码-分析和更改列表
作为输入,我得到了这样的列表(项目数量可能会发生变化): 若列表中接下来的两项是int和float,则在int之后插入列表字符串“X”,如下所示:Python 2.7 优化python代码-分析和更改列表,python-2.7,Python 2.7,作为输入,我得到了这样的列表(项目数量可能会发生变化): 若列表中接下来的两项是int和float,则在int之后插入列表字符串“X”,如下所示: [0.1, 1, 5, 8, 'X', 0.4, 2, 'X', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'X', 0.1] 这是我的代码,第一部分检查有多少项符合此条件,第二部分添加“X” c = 0 for i in range(len(b)): if type(b[i]) == float and type(b[i-1
[0.1, 1, 5, 8, 'X', 0.4, 2, 'X', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'X', 0.1]
这是我的代码,第一部分检查有多少项符合此条件,第二部分添加“X”
c = 0
for i in range(len(b)):
if type(b[i]) == float and type(b[i-1]) == int:
c += 1
st = 0
while st < c:
for i in range(len(b)):
if type(b[i]) == float and type(b[i-1]) == int:
b.insert(i, "X")
continue
st += 1
print b
您可以通过以下内容找到正确的插入索引:
indexes = [i for i, pair in enumerate(zip(b, b[1:])) if isinstance(pair[0], int) and isinstance(pair[1], float)]
zip()只是创建相邻值对
[(0.1, 1), (1, 5), (5, 8), (8, 0.4), (0.4, 2), (2, 0.3), (0.3, 0.4), (0.4, 1), (1, 2), (2, 2), (2, 3), (3, 4), (4, 5), (5, 0.1)]
枚举将跟踪索引和索引处的值。您可以使用该值将类型与isinstance进行比较,并仅保留与筛选器匹配的索引
对于您的示例,这将返回[3,5,13]
。但是,您不能简单地按顺序插入这些位置,因为索引将发生变化
因此,您可以:
[3,6,15]
您可以在一次通过中使用,每次获得匹配时设置一个标志,以便只生成同一个对象一次:
b = [0.1, 1, 5, 8, 0.4, 2, 0.3, 0.4, 1, 2, 2, 3, 4, 5, 0.1]
def insert_x(lst):
# create iterator
it = iter(lst)
# set matched to False initial and prev to the first element.
prev, matched = next(it), False
# start loop from second element.
for ele in it:
if isinstance(prev, int) and isinstance(ele, float):
yield prev
yield "X"
yield ele
matched = True
elif not matched:
yield prev
else:
matched = False
prev = ele
演示:
进行插入非常昂贵,有些时间安排:
In [12]: b
Out[12]: [0.1, 1, 5, 8, 'X', 0.4, 2, 'X', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'X', 0.1]
In [13]: from random import choice
In [14]: b = [choice(b) for _ in range(100000)]
In [15]: timeit list(insert_x(b))
10 loops, best of 3: 91.2 ms per loop
In [16]: %%timeit
....: indexes = [i for i, pair in enumerate(zip(b, b[1:])) if isinstance(pair[0], int) and isinstance(pair[1], float)]
....: c = b[:]
....: for i in indexes[::-1]:
....: c.insert(i+1, 'ok')
....:
1 loop, best of 3: 1.5 s per loop
In [17]: timeit b[:]
1000 loops, best of 3: 895 µs per loop
In [6]: indexes = [i for i, pair in enumerate(zip(b, b[1:])) if isinstance(pair[0], int) and isinstance(pair[1], float)]
In [7]: c = b[:]
In [8]: for i in indexes[::-1]:
...: c.insert(i+1, 'X')
...:
In [9]: c == list(insert_x(b)) # exact same result.
Out[9]: True
如果扣除
c=b[:]
的成本,它的速度仍然要慢得多。大约1.5秒vs 91毫秒 优化的具体原因是什么?我提出的第一个解决方案会在列表中迭代两次。是的,而你的第二个解决方案不会。那么为什么不使用它呢?这个问题不属于你SO@s_z_p:如果您只是将索引存储在一个附加列表中,然后按相反顺序迭代这些索引,并将其插入到b中,则可以使用第二种解决方案。你可以在我的答案的末尾看到它是如何工作的。另外,你不需要一个而True
和break
。因为你使用的是2.7
(根据标签),你可以使用itertools.izip
而不是zip来避免创建额外的列表。@s_z_p,每次插入,你所做的不仅仅是插入一个,你正在改变所有的元素,这显然是非常昂贵的b[:]=insert_x(b)
与您接受的答案中的insert逻辑相同,只是效率更高。@padraickenningham,写得不错,方法很棒。然而,我自己使用与您创建的相同的随机100000元素列表运行了相同的测试,并且我的方法在625-640ms内运行得非常一致。1.5秒是从哪里来的?@sberry,我实际上在那里又运行了一次,它的性能更差,使用python2和python3时,分别为~2.5秒和~100ms。您使用我的代码得到了什么时间?运行您的代码大约需要34-43毫秒,因此对于大型数据集(这是预期的)来说仍然要快一个数量级。我正在为py2使用jupyter控制台,并通过cmdline使用python-mtimeit-s“b=…”“我的代码在这里”和“这里”
运行了我的控制台,收到了非常相似的结果,大约625ms。哈,没错。我认为你的时间是9毫秒,不是90毫秒。
>>> for i in indexes[::-1]:
... b.insert(i+1, 'ok')
...
>>> b
[0.1, 1, 5, 8, 'ok', 0.4, 2, 'ok', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'ok', 0.1]
b = [0.1, 1, 5, 8, 0.4, 2, 0.3, 0.4, 1, 2, 2, 3, 4, 5, 0.1]
def insert_x(lst):
# create iterator
it = iter(lst)
# set matched to False initial and prev to the first element.
prev, matched = next(it), False
# start loop from second element.
for ele in it:
if isinstance(prev, int) and isinstance(ele, float):
yield prev
yield "X"
yield ele
matched = True
elif not matched:
yield prev
else:
matched = False
prev = ele
In [10]: b = [0.1, 1, 5, 8, 0.4, 2, 0.3, 0.4, 1, 2, 2, 3, 4, 5, 0.1]
In [11]: b[:] = insert_x(b)
In [12]: b
Out[12]: [0.1, 1, 5, 8, 'X', 0.4, 2, 'X', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'X', 0.1]
In [12]: b
Out[12]: [0.1, 1, 5, 8, 'X', 0.4, 2, 'X', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'X', 0.1]
In [13]: from random import choice
In [14]: b = [choice(b) for _ in range(100000)]
In [15]: timeit list(insert_x(b))
10 loops, best of 3: 91.2 ms per loop
In [16]: %%timeit
....: indexes = [i for i, pair in enumerate(zip(b, b[1:])) if isinstance(pair[0], int) and isinstance(pair[1], float)]
....: c = b[:]
....: for i in indexes[::-1]:
....: c.insert(i+1, 'ok')
....:
1 loop, best of 3: 1.5 s per loop
In [17]: timeit b[:]
1000 loops, best of 3: 895 µs per loop
In [6]: indexes = [i for i, pair in enumerate(zip(b, b[1:])) if isinstance(pair[0], int) and isinstance(pair[1], float)]
In [7]: c = b[:]
In [8]: for i in indexes[::-1]:
...: c.insert(i+1, 'X')
...:
In [9]: c == list(insert_x(b)) # exact same result.
Out[9]: True