[英]Python get current index of list comprehension without using enumerate
我有以下数据:
names = ['foo','bar','baz', 'spam', 'ham', 'jam']
indices =[0,2,3,4]
size = 3
并且想要创建索引在indices
中的名称列表。 该列表必须具有可变size
指定的size
。
通过这样做(错误的长度)我无法实现它:
selected_names = []
selected_names = [names[i] for i in indices if len(selected_names) <= size]
# Out[5]: ['foo', 'baz', 'spam', 'ham']
我不喜欢这个解决方案,因为在开头声明空列表并不优雅。
我可以做这个:
selected_names = [names[i] for x,i in enumerate(indices) if x <= size]
但这有点不可读,列表长度仍然是错误的。
是否有正确且更美观的方式来创建该列表? 也许是这样的?
#pseudo code
selected_names = [names[i] for i in indices if list_current_index < size]
enumerate
甚至不能解决这个问题,因为它会导致你在拉 size
元素时停止,而不是当你保留 size
元素时。 它似乎工作的唯一原因是你使用<= size
(实际上保持size + 1
元素)的测试,并且你的indices
碰巧是一个大于size
元素。 如果indices
较大或size
较小,则您的测试将无法按预期工作。
如果目标是保持size
元素,而不处理比需要更多的元素,那么最简单的方法(假设你不介意切片创建一个小的中间list
,这通常是好的)只是:
selected_names = [names[i] for i in indices[:size]]
如果indices
和size
很大,你可以使用itertools.islice
和生成器表达式来避免中间切片,使用更少的内存,但更多的CPU:
import itertools
selected_names = [names[i] for i in itertools.islice(indices, size)]
我可以找到的最快的选项,完全避免任何显式循环,是使用operator
模块 ,虽然它涉及参数传递的临时性,如果size
将会变得很大(数千及以上),这可能是一个坏主意:
import operator
selected_names = operator.itemgetter(*indices[:size])(names)
这将创建一个itemgetter
调用,将查找第一个size
从要素indices
,然后立即调用它的names
,返回一个tuple
的所有值(包裹itemgetter
在通话list
,如果你需要一个可变的list
的结果,而不是一个的tuple
)。 它还避免了CPython中的所有Python级循环; CPython中的C层仍然会出现循环,但C层的循环比Python层的任何循环运行得快得多。 对于简单的ipython
%timeit
测试, operator.itemgetter
方法获胜,比slice + list
comprehension少了大约24%(反过来比islice
+ list
comprehension快9%)。 对于较大的输入(我刚刚乘indices
和size
100), operator.itemgetter
获得了3倍的因素(片仍然跳动islice
,而是由一个毫无意义的边缘;在架空islice
大多是在安装,并且不增加有意义随着切片的数量上升)。
所有都相当于:
selected_names = [names[i] for i in indices][:size]
除了他们没有首先填写完整的list
,然后将其缩小到size
; 他们得到足够的条目并立即停止。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.