在不需要额外内存的情况下将python列表一分为二

在不需要额外内存的情况下将python列表一分为二,python,list,Python,List,我想将int列表l拆分为两个小列表l1,l2(我知道拆分点n) 我已经能够通过复制另一个列表中的l2元素,然后将它们从l中删除来执行拆分,但这需要内存中至少有n+n/2元素的空间,这是不可承受的,因为l很大 有人有解决办法吗?试试这个怎么样 class mylist(list): def split_by_position_n(self, n): return self[:int(n)], self[int(n):] 然后,l=mylist(范围(1,10)) 您可以使

我想将
int
列表
l
拆分为两个小列表
l1
l2
(我知道拆分点
n

我已经能够通过复制另一个列表中的
l2
元素,然后将它们从
l
中删除来执行拆分,但这需要内存中至少有
n+n/2
元素的空间,这是不可承受的,因为
l
很大

有人有解决办法吗?

试试这个怎么样

class mylist(list):
    def split_by_position_n(self, n):
        return self[:int(n)], self[int(n):]
然后,
l=mylist(范围(1,10))


您可以使用at
n
对列表进行切片。切片对象是惰性的,只有在迭代时才会加载到内存中:

from itertools import islice

def split_list(lst, n):
    return islice(lst, n), islice(lst, n, None)

A, B = split_list(range(10), 5)

print(list(A))
# [0, 1, 2, 3, 4]
print(list(B))
# [5, 6, 7, 8, 9]
海洛阿雷托

这是我的解决方案:

list = [1,2,3,4,5,6,7,8,9]
l1 = list[0:n]
l2 = list[n:]
  • 列表是元素的列表
  • n是第一个列表(拆分点索引)中所需的元素数
列表[0:n]将返回列表的前n项

list[n:]将返回列表的其余部分

希望对你有帮助


编辑:如果您担心内存问题,可以在拆分列表后将其删除。。即使您可以在代码中使用list[0:n]/list[n:],也不会占用更多内存

如果您不想在较小的列表上花费额外的内存,有两种可能:

  • 您可以在创建较小的列表时销毁/减少原始列表。您可以使用,在两端提供O(1)移除和插入:

    >>> from collections import deque
    >>> deq = deque(range(20))
    >>> front = deque(deq.popleft() for _ in range(10))
    >>> front
    deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    >>> deq  # original list reduced, can be used as 2nd list
    deque([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
    
  • 或者,您可以在较小列表的部分上创建两个视图,这意味着如果较小列表被修改,原始列表将被更改,反之亦然。例如,对数字使用
    numpy.array
    ,并在该数组上创建切片(即视图):

    >>> import numpy as np
    >>> arr = np.array(range(20))
    >>> front = arr[:10]
    >>> back = arr[10:]
    >>> front[3] = 100
    >>> arr  # original list modified
    array([  0,   1,   2, 100,   4,   5,   6,   7,   8,   9,  10,  11,  12,
            13,  14,  15,  16,  17,  18,  19])
    
  • 如果必须使用普通Python
    list
    ,也可以使用
    list.pop
    。但是,如中所述,您不应使用
    pop(0)
    ,因为每次弹出元素时,都必须重新组织整个列表,从而为您提供O(n²)来提取列表的一半。相反,使用
    pop()
    从列表末尾弹出。要恢复原始顺序,可以先弹出到临时列表中,然后从该列表中弹出,将其反转两次

    >>> lst = list(range(10))
    >>> tmp = [lst.pop() for _ in range(5)]
    >>> front, back = lst, [tmp.pop() for _ in range(len(tmp))]
    >>> front, back
    ([0, 1, 2, 3, 4], [5, 6, 7, 8, 9])
    

    我提出了一个简单的解决方案。那怎么办

    l1 = [l.pop(0) for i in range(n)]
    

    它似乎可以工作,不需要额外的内存。

    可能会重复为什么要拆分?您可以构造某种类型的“视图”,将列表的一部分视为完整列表issue@asongtoruin:此问题更具体地说明了如何在不造成巨大内存负担的情况下执行此操作。@WillemVanonSeuming for a view似乎是一个不错的选择这与我的第一个解决方案类似,但请注意,在常规列表中,
    pop(0)
    非常浪费。您不需要额外的内存,但对于每个
    pop
    ,所有元素都必须重新定位。最好使用
    deque
    。事实上,甚至在列表中提到了
    pop(0)
    的O(n)内存开销,这正是您试图避免的。(误读文档,这是移动内存的O(n)开销,不是O(n)内存开销,但仍然是弹出一半列表的二次复杂度,如果列表很长,这是非常糟糕的。)@tobias_k
    pop()
    仅限?移动元件是否需要O(n)成本?我真的不需要让元素保持有序。
    pop()
    不应该那么糟糕;随着列表的缩小,它可能仍会不时地进行一些秘密的数据重组,
    li
    中的元素将被反转,但除此之外。。。为了确保你只需要尝试一下你的大名单。尽管如此,使用
    deque
    有什么错?好吧
    deque
    不是
    list
    list
    的子类,我一定要使用
    deque
    类,而不使用
    list
    类的所有特性,或者做一些类似
    deq=deque(l)
    然后
    l=list(deq)
    。在你的回答中把我的选择作为第三个选择,连同这些考虑因素,会有帮助吗?
    l1 = [l.pop(0) for i in range(n)]