Как инициализировать двумерный массив в Python?
Я начинаю python, и я пытаюсь использовать двумерный список, который я изначально заполняю одной и той же переменной в каждом месте. Я придумал вот что:--2-->
def initialize_twodlist(foo):
twod_list = []
new = []
for i in range (0, 10):
for j in range (0, 10):
new.append(foo)
twod_list.append(new)
new = []
Он дает желаемый результат, но чувствует себя как обходной путь. Есть ли более простой / короткий / элегантный способ сделать это?
20 ответов
шаблон, который часто появлялся в Python, был
bar = []
for item in some_iterable:
bar.append(SOME EXPRESSION)
который помог мотивировать введение списка понимания, которые преобразуют этот фрагмент в
bar = [SOME EXPRESSION for item in some_iterable]
который короче и иногда яснее. Обычно вы привыкаете распознавать их и часто заменяете циклы пониманием.
ваш код следует этому шаблону дважды
twod_list = [] \
for i in range (0, 10): \
new = [] \ can be replaced } this too
for j in range (0, 10): } with a list /
new.append(foo) / comprehension /
twod_list.append(new) /
вы можете использовать понимание:
x = [[foo for i in range(10)] for j in range(10)]
# x is now a 10x10 array of 'foo' (which can depend on i and j if you want)
этот путь быстрее чем вложенный список постижений
[x[:] for x in [[foo] * 10] * 10] # for immutable foo!
вот некоторые тайминги python3, для малых и больших списков
$python3 -m timeit '[x[:] for x in [[1] * 10] * 10]'
1000000 loops, best of 3: 1.55 usec per loop
$ python3 -m timeit '[[1 for i in range(10)] for j in range(10)]'
100000 loops, best of 3: 6.44 usec per loop
$ python3 -m timeit '[x[:] for x in [[1] * 1000] * 1000]'
100 loops, best of 3: 5.5 msec per loop
$ python3 -m timeit '[[1 for i in range(1000)] for j in range(1000)]'
10 loops, best of 3: 27 msec per loop
объяснение:
[[foo]*10]*10
создает список одного и того же объекта, повторенный 10 раз. Вы не можете просто использовать это, потому что изменение одного элемента изменит тот же элемент в каждой строке!
x[:]
эквивалентно list(X)
но немного эффективнее, так как он избегает имени уважать. В любом случае, он создает мелкую копию каждой строки, поэтому теперь все элементы независимы.
все элементы одинаковы foo
объект, хотя, так что если foo
изменчиво, вы не можете использовать эту схему. вам придется использовать
import copy
[[copy.deepcopy(foo) for x in range(10)] for y in range(10)]
или предполагая класс (или функцию) Foo
возвращает foo
s
[[Foo() for x in range(10)] for y in range(10)]
для инициализации двумерного массива в Python:
a = [[0 for x in range(columns)] for y in range(rows)]
Не используйте [[v] * n]*n, это ловушка!
>>> a = [[0]*3]*3
>>> a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[0][0]=1
>>> a
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
но t = [[0]*3 для i в диапазоне (3)] велик
обычно, когда вам нужны многомерные массивы, вам нужен не список списков, а скорее массив numpy или, возможно, dict.
например, с numpy вы бы сделали что-то вроде
import numpy
a = numpy.empty((10, 10))
a.fill(foo)
вы можете сделать это:
[[element] * numcols] * numrows
например:
>>> [['a'] *3] * 2
[['a', 'a', 'a'], ['a', 'a', 'a']]
но это имеет нежелательный побочный эффект:
>>> b = [['a']*3]*3
>>> b
[['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
>>> b[1][1]
'a'
>>> b[1][1] = 'b'
>>> b
[['a', 'b', 'a'], ['a', 'b', 'a'], ['a', 'b', 'a']]
Если это малонаселенный массив, вам может быть лучше использовать словарь с кортежем:
dict = {}
key = (a,b)
dict[key] = value
...
используйте самый простой думать, чтобы создать это.
wtod_list = []
и добавить размер:
wtod_list = [[0 for x in xrange(10))] for x in xrange(10)]
или если мы хотим объявить размер во-первых. мы используем только:
wtod_list = [[0 for x in xrange(10))] for x in xrange(10)]
неверный подход: [[Нет*m]*n]
>>> m, n = map(int, raw_input().split())
5 5
>>> x[0][0] = 34
>>> x
[[34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None], [34, None, None, None, None]]
>>> id(x[0][0])
140416461589776
>>> id(x[3][0])
140416461589776
при таком подходе python не позволяет создавать различное адресное пространство для внешних столбцов и приведет к различным неправильным действиям, чем вы ожидаете.
правильный подход, но с исключением:
y = [[0 for i in range(m)] for j in range(n)]
>>> id(y[0][0]) == id(y[1][0])
False
это хороший подход, но есть исключение, если вы установите значение по умолчанию None
>>> r = [[None for i in range(5)] for j in range(5)]
>>> r
[[None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None], [None, None, None, None, None]]
>>> id(r[0][0]) == id(r[2][0])
True
поэтому установите значение по умолчанию правильно, используя это подход.
абсолютно правильное:
следуйте ответу микрофона двойная петля.
как указали @Arnab и @Mike, массив не является списком. Несколько отличий: 1) массивы фиксированного размера во время инициализации 2) массивы обычно поддерживают меньшие операции, чем список.
возможно, в большинстве случаев это перебор, но вот базовая реализация 2D-массива, которая использует реализацию аппаратного массива с использованием Python ctypes(C-библиотеки)
import ctypes
class Array:
def __init__(self,size,foo): #foo is the initial value
self._size = size
ArrayType = ctypes.py_object * size
self._array = ArrayType()
for i in range(size):
self._array[i] = foo
def __getitem__(self,index):
return self._array[index]
def __setitem__(self,index,value):
self._array[index] = value
def __len__(self):
return self._size
class TwoDArray:
def __init__(self,columns,rows,foo):
self._2dArray = Array(rows,foo)
for i in range(rows):
self._2dArray[i] = Array(columns,foo)
def numRows(self):
return len(self._2dArray)
def numCols(self):
return len((self._2dArray)[0])
def __getitem__(self,indexTuple):
row = indexTuple[0]
col = indexTuple[1]
assert row >= 0 and row < self.numRows() \
and col >=0 and col < self.numCols(),\
"Array script out of range"
return ((self._2dArray)[row])[col]
if(__name__ == "__main__"):
twodArray = TwoDArray(4,5,5)#sample input
print(twodArray[2,3])
twod_list = [[foo for _ in range(m)] for _ in range(n)]
для n-количество строк, m-количество столбцов, foo-значение.
Это лучшее что я нашел для обучения новых программистов, и без использования дополнительных библиотек. Но мне хотелось бы чего-нибудь получше.
def initialize_twodlist(value):
list=[]
for row in range(10):
list.append([value]*10)
return list
вот более простой способ :
import numpy as np
twoD = np.array([[]*m]*n)
для инициализации всех ячеек с любым значением " x " Используйте:
twoD = np.array([[x]*m]*n
часто я использую этот подход для инициализации 2-мерный массив
n=[[int(x) for x in input().split()] for i in range(int(input())]
общий шаблон для добавления размеров может быть нарисован из этой серии:
x = 0
mat1 = []
for i in range(3):
mat1.append(x)
x+=1
print(mat1)
x=0
mat2 = []
for i in range(3):
tmp = []
for j in range(4):
tmp.append(x)
x+=1
mat2.append(tmp)
print(mat2)
x=0
mat3 = []
for i in range(3):
tmp = []
for j in range(4):
tmp2 = []
for k in range(5):
tmp2.append(x)
x+=1
tmp.append(tmp2)
mat3.append(tmp)
print(mat3)
from random import randint
l = []
for i in range(10):
k=[]
for j in range(10):
a= randint(1,100)
k.append(a)
l.append(k)
print(l)
print(max(l[2]))
b = []
for i in range(10):
a = l[i][5]
b.append(a)
print(min(b))