用“扁平化”索引访问2D列表的好方法是什么?

时间:2019-07-02 14:25:40

标签: python list

假设我们有一个2D,3x3的列表:

list = [[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]]

建议使用“扁平化”索引访问list元素的推荐方法是什么?

我的意思是,我只有0到9之间的数字。如何访问相应的list[i][j]元素?

5 个答案:

答案 0 :(得分:3)

您可以使用除法和取模来计算2D坐标(仅在所有子列表的大小相同时才有效)

def get_item(lst,i):    
    return(lst[i//len(lst[0])][i%len(lst[0])])

请注意,将列表扁平化以访问项目是O(n**2)的复杂性,而此方法是O(1)

如果子列表的长度可变,则必须先找到子列表,并且不能使用除法。但是一旦找到正确的子列表,您就可以访问O(1)

lst = [[1, 2, 3, 4],
        [5, 6],
        [7,8,9,10]]

def get_item(lst,i):
    current = 0
    for sublist in lst:
        index = i - current
        if 0 <= index < len(sublist):
            return sublist[index]
        current += len(sublist)
    raise Exception("index out of range {}".format(i))

print(get_item(lst,0),get_item(lst,6),get_item(lst,9))

打印:1 7 10

答案 1 :(得分:1)

这是一条简短的命令,但是效率较低:

<svg>
 <defs>
  <radialGradient id="radialGradient827" cx="105.22" cy="144.2" r="51.989" gradientTransform="matrix(.23275 1.7456 -.93805 .12507 214.81 -67.26)" gradientUnits="userSpaceOnUse">
   <stop stop-color="#00f" offset="0"/>
   <stop stop-color="#00f3ff" offset="1"/>
  </radialGradient>
 </defs>
 <g transform="translate(-60.376 -63.391)">
  <path id="blob" transform="matrix(1.3569 0 0 1.3569 -2.3105 -31.738)" d="m52.019 88.923c5.9206-9.9143 16.696-16.529 28.107-18.297 11.411-1.7677 23.305 1.0814 33.237 6.9726 9.9318 5.8912 17.964 14.688 23.862 24.615 5.898 9.9278 9.7369 20.973 12.329 32.226 2.527 10.969 3.9032 22.276 3.0655 33.502-0.83773 11.225-3.9548 22.389-9.9198 31.935-5.965 9.5462-14.884 17.395-25.477 21.204s-22.841 3.3361-32.693-2.1096c-5.4164-2.9941-10.001-7.3752-13.622-12.394-3.6211-5.019-6.3053-10.669-8.3576-16.508-4.1048-11.677-5.7091-24.058-8.4789-36.122-2.4949-10.866-5.9526-21.549-7.3169-32.614-1.3643-11.065-0.45314-22.838 5.2631-32.41z" fill="url(#radialGradient827)" stroke-width="0"/>
 </g>
</svg>

输出:

lst = [[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]]

#Get the index no. 5 from 2d list
sum(lst, [])[5]

答案 2 :(得分:0)

您可以使用itertools.chain

from itertools import chain

lst = [[1, 2, 3],
         [4, 5, 6],
         [7, 8, 9]]

for i, x in enumerate(chain(*lst)):
    print(i, x)

0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9

因此要利用扁平化索引:

# you can just match the index explicitly
for i, x in enumerate(chain(*lst)):
    if i==5:
        break

x
# 6

# or you can store in a list 
flattened = list(chain(*lst))

flattened[5]
# 6

答案 3 :(得分:0)

您可以使用numpy.reshape从2D数组生成1D数组。

import numpy

in_list = [[1,2,3],[4,5,6],[7,8,9]]
out_list = numpy.reshape(in_list, 9).tolist()

print(in_list)
#[[1,2,3],[4,5,6],[7,8,9]]

print(out_list)
#[1,2,3,4,5,6,7,8,9]

然后,您可以将调整大小的数组作为一维数组访问

print(out_list[2])
#2

答案 4 :(得分:0)

对于矩形矩阵,可以使用divmod合并行索引和列索引访问复杂度: O(1)

matrix = [[1, 2, 3,],
          [10,11,12],
          [21,22,23]]

r,c = divmod(6,len(matrix[0]))
value = matrix[r][c]
print(value) # 21

对于不规则的列表列表,只要大小不变,您都可以构建一个间接列表并将其用于将平面位置转换为行索引和列索引访问复杂度: O(1) 索引复杂度O(N)(N =元素总数)

matrix = [[1, 2, 3, 4 ,5],
          [10,11,12],
          [21,22,23,24]]

indx = [ (r,c) for r,row in enumerate(matrix) for c in range(len(row)) ]
pos   = 8
r,c   = indx[pos]
value = matrix[r][c]

print(value) # 21

创建indx列表后,访问元素实际上将与矩形矩阵方法(整数除法和模)一样快。

注意,只要更改列表的大小或其中的任何行,就必须重新创建间接列表(indx)。

如果矩阵更改(大小)的次数比使用固定位置访问矩阵的次数更多,则可以创建一个函数来返回索引访问复杂度: O(R)

def rowCol(m,p):
    for r,row in enumerate(m):
        if p<len(row): return r,p
        p-=len(row)

r,c = rowCol(matrix,8)
value = matrix[r][c]
print(value) 

这将比准备好的indx变量访问慢很多,因此您可能想使用混合方法,即在每次更改后清除索引,然后仅根据需要重建索引(当函数为

另一个可以更快地建立索引但访问速度稍慢的替代方法是创建仅具有矩阵行的累积大小的索引。然后,您可以使用二进制搜索算法查找行,并使用简单的减法查找列访问复杂度: O(log(R)) 索引复杂度: O(R)

matrix = [[1, 2, 3,],
          [10,11,12,13,14],
          [21,22,23,24]]

from itertools import accumulate
from bisect import bisect_left
indx = [0]+list(accumulate(map(len,matrix)))

pos   = 8
r     = bisect_left(indx,pos+1)-1
c     = pos - indx[r]
value = matrix[r][c]
print(pos,r,c,value) # 21

这比完整的坐标索引访问慢,但是它将消耗更少的内存,并且仍然比迭代函数快得多(本质上是顺序执行相同的功能)