使用Python通过索引创建子列表的新列表

40

一个列表:

a = ['a', 'b', 'c', 3, 4, 'd', 6, 7, 8]

我希望用 a[0:2],a[4], a[6:] 的子集来创建一个列表,即我想要一个列表['a', 'b', 4, 6, 7, 8]


7
如果你在你的示例中将 , 改成 + 来进行待办事项连接,那么你就做到了... - Jon Clements
7
@JonClements:几乎就是这样。我想应该是a[4:5][a[4]]。但你的道义是正确的。 :^) - DSM
谢谢Jon -- 我就是这么做的,但是遇到了错误;DSM -- 谢谢,解决了我的问题。 - user2783615
5个回答

44

假设

a = ['a', 'b', 'c', 3, 4, 'd', 6, 7, 8]

索引列表存储在

b= [0, 1, 2, 4, 6, 7, 8]

那么一个简单的一行解决方案将是:

c = [a[i] for i in b]

35

尝试使用 new_list = a[0:2] + [a[4]] + a[6:]

或者更一般地,类似这样:

from itertools import chain
new_list = list(chain(a[0:2], [a[4]], a[6:]))

这也适用于其他序列,并且很可能更快。

或者您可以这样做:

def chain_elements_or_slices(*elements_or_slices):
    new_list = []
    for i in elements_or_slices:
        if isinstance(i, list):
            new_list.extend(i)
        else:
            new_list.append(i)
    return new_list

new_list = chain_elements_or_slices(a[0:2], a[4], a[6:])

但要小心,如果你的列表中有些元素本身就是列表,那么这将导致问题。为了解决这个问题,可以使用之前提到过的解决方案之一,或者用a[4:5](或更一般地用a[n:n+1])代替a[4]


谢谢,第二个解决方案很棒。 - user2783615
再次感谢您提供的函数--在参数中*的用法是什么? - user2783615
它(我相信它被称为splat操作符)用于使您可以在函数中拥有任意数量的参数。请参见此链接:https://dev59.com/rXA75IYBdhLWcg3wP2kg - rlms
@user2783615 没问题(不过我建议你小心使用那个解决方案,因为它对于列表的列表会失败)。 - rlms

1

这个帖子已经很旧了,我不知道在当时是否存在这种方法,但是我在2022年找到的最快解决方案还没有在答案中提到。

我的示例列表包含从1到6的整数,我想从这个列表中检索4个项目。

我在安装有Python 3.7.4的Windows 10系统上使用Jupyter Notebook / iPython的%timeit功能。

我添加了一个numpy方法只是为了看看它有多快。在原始问题的混合类型集合中可能需要更多时间。

最快的解决方案似乎是来自operator模块(标准库)的itemgetter。如果返回值是元组或列表都可以,直接使用itemgetter,否则使用列表转换。两种情况都比其他解决方案快。

from itertools import chain
import numpy as np
from operator import itemgetter
# 
my_list = [1,2,3,4,5,6]
item_indices = [2, 0, 1, 5]
# 
%timeit itemgetter(*item_indices)(my_list)
%timeit list(itemgetter(*item_indices)(my_list))
%timeit [my_list[item] for item in item_indices]
%timeit list(np.array(my_list)[item_indices])
%timeit list(chain(my_list[2:3], my_list[0:1], my_list[1:2], my_list[5:6]))

输出结果如下:

184 ns ± 14.5 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
251 ns ± 11.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
283 ns ± 85.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
4.3 µs ± 260 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
663 ns ± 49.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

我对根据列表大小和要提取的项目数量确定最快解决方案的可能偏差很感兴趣,但这是我当前项目的典型用例。 如果有人有时间进一步调查,请告诉我。


1
以下定义可能比最初提出的解决方案更有效。
def new_list_from_intervals(original_list, *intervals):
    n = sum(j - i for i, j in intervals)
    new_list = [None] * n
    index = 0
    for i, j in intervals :
        for k in range(i, j) :
            new_list[index] = original_list[k]
            index += 1

    return new_list

然后您可以像下面这样使用它。
new_list = new_list_from_intervals(original_list, (0,2), (4,5), (6, len(original_list)))

0

我有类似的需求,但是我不想使用切片,我只想引用索引。 这是我所做的:

numbers = ['3.1', '2,832', '4.5', '534,459', '8.2', '2,176,777', '8.6']
indices = [2, 3, 4, 6]

subset = [numbers[i] for i in indices]

print(subset)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接