Для прямоугольной матрицы вы можете использовать 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
Доступ к нему медленнее, чем полное индексирование координат, но он будет занимать меньше памяти и все равно будет намного быстрее, чем итеративная функция (которая, по сути, делает то же самое последовательно)