繁体   English   中英

Python不使用枚举就获得列表推导的当前索引

[英]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]]

如果indicessize很大,你可以使用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%)。 对于较大的输入(我刚刚乘indicessize 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM