在Python中,我有一个列表列表作为输入:
input = [[0,1,2],[0,3,4,5],[0,6]]
实际上,子列表的数量是数万。每个子列表的长度可以有很大的不同,从零或一个值到数百个值。
我想将输入数据作为2D结构传递给处理它的Cython模块。我希望在多个内核上处理数据,因此我将prange
与nogil=True
一起使用:
from cython.parallel import prange
cpdef int my_func(long[:,:] arr):
cdef int i,j
for i in prange(arr.shape[0], nogil=True):
for j in range(arr.shape[1]):
# Do something
pass
return 42
我看到以下解决方案:
my_func
以接受列表列表。问题在于,部分代码是在没有GIL的情况下执行的,因此无法访问python对象。有人对如何解决此问题有建议,最好是带有代码的建议?
答案 0 :(得分:4)
我可能会选择一个扁平化的数组,其中单个列表的开始存储在一个辅助数组中,与csr-matrices相似。
这里是一个示例,该示例如何从列表列表构造此数据结构(使用numpy,但您也可以使用array.array
;它实际上并没有针对速度进行优化),只是为了给您提供一个概念:
import numpy as np
def flatten_list_of_lists(lst_of_lsts):
N = sum(map(len, lst_of_lsts)) # number of elements in the flattened array
starts = np.empty(len(lst_of_lsts)+1, dtype=np.uint64) # needs place for one sentinel
values = np.empty(N, dtype=np.int64)
starts[0], cnt = 0, 0
for i,lst in enumerate(lst_of_lsts):
for el in lst:
values[cnt] = el
cnt += 1 # update index in the flattened array for the next element
starts[i+1] = cnt # remember the start of the next list
return starts, values
因此对于您的示例,将产生以下结果:
# starts values
(array([0, 3, 7, 9], dtype=uint64), array([0, 1, 2, 0, 3, 4, 5, 0, 6]))
您会看到:有3个子列表,分别从0
,3
和7
到3
(差异starts[1]-starts[0]
),{{1} }和4
个元素。
这是可以使用这些数据的方式:
2