Как инициализировать двумерный массив в 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 возвращает foos

[[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)] велик


[[foo for x in xrange(10)] for y in xrange(10)]

обычно, когда вам нужны многомерные массивы, вам нужен не список списков, а скорее массив 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

поэтому установите значение по умолчанию правильно, используя это подход.

абсолютно правильное:

следуйте ответу микрофона двойная петля.


t = [ [0]*10 for i in [0]*10]

для каждого элемента [0]*10 будет создан ..


как указали @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])

Matrix={}
for i in range(0,3):
  for j in range(0,3):
    Matrix[i,j] = raw_input("Enter the matrix:")

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))