Как инициализировать двумерный массив в Python?


262

Я начинаю Python и пытаюсь использовать двумерный список, который я изначально заполняю одной и той же переменной в каждом месте. Я придумал это:

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 = []

Это дает желаемый результат, но чувствует себя как обходной путь. Есть ли более простой / короткий / более элегантный способ сделать это?


7
Просто маленький (или значительный, в зависимости от того, кто смотрит) придирка: списки не являются массивами. Если вам нужны массивы, используйте numpy.
Арнаб Датта

Этот вопрос похож : он обсуждает инициализацию многомерных массивов в Python.
Андерсон Грин,

@ArnabDatta Как бы вы инициализировали многомерный массив в numpy, тогда?
Андерсон Грин,


Вы можете расположить данные в массив, подобный структуре, в Python по умолчанию, но это не так эффективно и полезно, как массив NumPy. Особенно, если вы хотите иметь дело с большими наборами данных. Вот некоторая документация docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamer

Ответы:


376

Шаблон, который часто появлялся в 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)                           /

35
Кстати, [[foo] * 10 для x в xrange (10)] можно использовать, чтобы избавиться от одного понимания. Проблема в том, что умножение делает поверхностную копию, поэтому new = [foo] * 10 new = [new] * 10 даст вам список, содержащий один и тот же список десять раз.
Скотт Волчок

8
Точно так же [foo] * 10это список с одинаковыми точными foo10 разами, что может или не может быть важным.
Майк Грэм,

2
мы можем использовать простейшую вещь: wtod_list = [[0 для x в xrange (10))] для x в xrange (10)]
indi60

2
Тем не менее, никогда не повредит показать кому-то, как выглядит рыба.
Csteele5

2
Для комментариев Майка Грэма о [foo] * 10: Это означает , что это не будет работать , если вы заполняете массив со случайными числами (Равняется [random.randint(1,2)] * 10до [1] * 10или [2] * 10это означает , что вы получите массив всех 1S или 2s, вместо случайного массива.
Цзы Ли

226

Вы можете использовать понимание списка :

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)

1
так как размер (10) такой же, его хорошо, если не вложенный цикл должен стоять первым [foo для j в диапазоне (range_of_j)] для i в диапазоне (range_of_i)]
Динешкумар

2
Ответ на этот вопрос хорошо , но я работает с перебираемым iдля строк и jстолбцов, я думаю , что это должно быть лучше своп iи jв вашем синтаксисе для лучшего понимания и изменение диапазона 2 разных номеров.
DragonKnight

139

Не используйте [[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 for i in range(3)]

прекрасно работает.


26
да, я тоже попал в эту ловушку. Это потому что *копирует addressобъект (список).
Чинуй

1
Проголосовал, так как это меня достало. Чтобы быть понятнее [[0] * col for _ in range(row)].
Абхиджит Саркар

138

Этот способ быстрее, чем понимание вложенного списка

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

4
@ Майк, ты пропустил роль жирным шрифтом? если foo изменчив, ни один из других ответов здесь не сработает (если вы вообще не мутируете foo)
John La Rooy

1
Вы не можете правильно копировать произвольные объекты, используя copy.deepcopy. Вам нужен план, соответствующий вашим данным, если у вас есть произвольный изменяемый объект.
Майк Грэм

1
Если вам нужна
такая высокая

1
@JohnLaRooy я думаю, что вы обменялись xи y. Не должно ли быть[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
user3085931

1
@Nils [foo]*10не создает 10 различных объектов - но легко пропустить разницу в случае, когда foo является неизменным, например, intor или str.
Джон Ла Рой

62

Чтобы инициализировать двумерный массив в Python:

a = [[0 for x in range(columns)] for y in range(rows)]

4
Чтобы инициализировать все значения в 0, просто используйте a = [[0 for x in range(columns)] for y in range(rows)].
ZX9

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

1
xrange () был удален в python3.5
MiaeKim

почему это не работает: [0 * col] * строка. Когда я изменяю какой-то элемент, он копируется в других местах. Но я не понимаю, почему?
код Muncher

Потому что это делает то же самое, что и код в вопросе.
Игнасио Васкес-Абрамс

2
@codemuncher Причина, по [[0] * col] * rowкоторой не получается то, что вы хотите, заключается в том, что когда вы инициализируете двухмерный список таким образом, Python не будет создавать отдельные копии каждой строки. Вместо этого он будет инициировать внешний список с указателями на ту же копию [0]*col. Любое изменение, внесенное вами в одну из строк, будет отражено в оставшихся строках, поскольку все они фактически указывают на одни и те же данные в памяти.
Адди

Просто мысль, но разве не все эти списки бесполезны для добавления? То есть. если я хочу пустой 2D-список измерения 3 * 6 и хочу добавить в индекс [0] [0], [1] [0], [2] [0] и так далее, чтобы заполнить все 18 элементов, ни один из эти ответы будут работать правильно?
mLstudent33

22

Обычно, когда вам нужны многомерные массивы, вам не нужен список списков, а скорее массив с пустыми данными или, возможно, dict.

Например, с NumPy вы бы сделать что-то вроде

import numpy
a = numpy.empty((10, 10))
a.fill(foo)

2
Хотя numpyэто здорово, я думаю, что это может быть немного излишним для новичка.
Эстебан Кюбер

3
Numpy предоставляет многомерный тип массива. Создание хорошего многомерного массива из списков возможно, но менее полезно и труднее для новичка, чем использование numpy. Вложенные списки хороши для некоторых приложений, но обычно это не то, что кому-то нужен 2d-массив.
Майк Грэм

1
после нескольких лет работы над серьезными приложениями на python причуды стандартных массивов python, кажется, оправдывают дальнейшее развитие numpy. +1
Джавадба

12

Вы можете сделать только это:

[[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']]

11
По моему опыту, этот «нежелательный» эффект часто является источником некоторых очень плохих логических ошибок. На мой взгляд, такого подхода следует избегать, вместо этого ответ @ Vipul намного лучше.
Алан Тьюринг

этот подход работает хорошо, почему в комментариях некоторые люди говорят, что это плохо?
Браво

1
Из-за недостаточного побочного эффекта вы не можете рассматривать его как матрицу. Если вам не нужно изменять содержимое, все будет хорошо.
hithwen

9
twod_list = [[foo for _ in range(m)] for _ in range(n)]

для n это количество строк, а m это номер столбца, а foo это значение.


8

Если это малонаселенный массив, вам лучше использовать словарь с кортежем:

dict = {}
key = (a,b)
dict[key] = value
...

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

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


4

Неверный подход: [[None * 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

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

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

Следуйте ответу Майка двойной петли .


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

1
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и / или как этот код отвечает на вопрос, повышает его долгосрочную ценность.
Ajean

3

Для инициализации 2-мерного массива используйте: arr = [[]*m for i in range(n)]

на самом деле, arr = [[]*m]*nсоздаст 2D массив, в котором все n массивов будут указывать на один и тот же массив, поэтому любое изменение значения в любом элементе будет отражено во всех n списках

для более подробного объяснения посетите: https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/


3

используйте простейшее мышление, чтобы создать это.

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

1

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

1

Я понял одну важную вещь: при инициализации массива (в любом измерении) мы должны задать значение по умолчанию для всех позиций массива. Тогда только инициализация завершается. После этого мы можем изменить или получить новые значения для любой позиции массива. Код ниже работал для меня отлично

N=7
F=2

#INITIALIZATION of 7 x 2 array with deafult value as 0
ar=[[0]*F for x in range(N)]

#RECEIVING NEW VALUES TO THE INITIALIZED ARRAY
for i in range(N):
    for j in range(F):
        ar[i][j]=int(input())
print(ar)

1

Если вы используете numpy , вы можете легко создавать 2d массивы:

import numpy as np

row = 3
col = 5
num = 10
x = np.full((row, col), num)

Икс

array([[10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10],
       [10, 10, 10, 10, 10]])

1
row=5
col=5
[[x]*col for x in [b for b in range(row)]]

Вышеприведенное даст вам 5x5 2D массив

[[0, 0, 0, 0, 0],
 [1, 1, 1, 1, 1],
 [2, 2, 2, 2, 2],
 [3, 3, 3, 3, 3],
 [4, 4, 4, 4, 4]]

Это использует понимание вложенного списка. Разбивка, как показано ниже:

[[x]*col for x in [b for b in range(row)]]

[x] * col -> конечное выражение, которое вычисляется
для x in -> x будет значением, предоставленным итератором
[b для b in range (row)]] -> Iterator.

[b для b в диапазоне (строка)]] это будет оцениваться как [0,1,2,3,4], так как строка = 5,
так что теперь это упрощает

[[x]*col for x in [0,1,2,3,4]]

Это даст оценку [[0] * 5 для x в [0,1,2,3,4]] -> с x = 0 1-я итерация
[[1] * 5 для x в [0,1,2, 3,4]] -> с x = 1 2-й итерацией
[[2] * 5 для x в [0,1,2,3,4]] -> с x = 2 3-й итерацией
[[3] * 5 для x в [0,1,2,3,4]] -> с x = 3 4-я итерация
[[4] * 5 для x в [0,1,2,3,4]] -> с x = 4 5-я итерация


0

Это лучшее, что я нашел для обучения новых программистов и без использования дополнительных библиотек. Я хотел бы что-нибудь получше.

def initialize_twodlist(value):
    list=[]
    for row in range(10):
        list.append([value]*10)
    return list

0

Вот более простой способ:

import numpy as np
twoD = np.array([[]*m]*n)

Для инициализации всех ячеек с любым значением «x» используйте:

twoD = np.array([[x]*m]*n

0

Часто я использую этот подход для инициализации 2-мерного массива

n=[[int(x) for x in input().split()] for i in range(int(input())]


0

Общий шаблон для добавления размеров можно извлечь из этой серии:

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)

Добро пожаловать в ТАК. На этот вопрос уже принят массово принятый ответ. На первый взгляд, этот пост фактически не отвечает на вопрос. См. Stackoverflow.com/help/how-to-answer для руководства.
Ник

0

Вы можете попробовать это [[0] * 10] * 10. Это вернет 2d массив из 10 строк и 10 столбцов со значением 0 для каждой ячейки.


Это, по существу , тот же ответ , как stackoverflow.com/a/25601284/2413201 ...
Armali

2
Это создает массив из 10 указателей на одну строку. Если вы это сделаете, a = [[0]*10]*10то a[0][0] = 1увидите, что первый элемент в каждом ряду теперь равен 1
andnik


0

Другой способ - использовать словарь для хранения двумерного массива.

twoD = {}
twoD[0,0] = 0
print(twoD[0,0]) # ===> prints 0

Это просто может содержать любые 1D, 2D значения и для инициализации этого 0или любого другого значения int, использовать коллекции .

import collections
twoD = collections.defaultdict(int)
print(twoD[0,0]) # ==> prints 0
twoD[1,1] = 1
print(twoD[1,1]) # ==> prints 1

0

Код:

num_rows, num_cols = 4, 2
initial_val = 0
matrix = [[initial_val] * num_cols for _ in range(num_rows)]
print(matrix) 
# [[0, 0], [0, 0], [0, 0], [0, 0]]

initial_val должен быть неизменным.


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

4
Пожалуйста, добавьте текст, описывающий, что делает ваш код.
whackamadoodle3000

1
Обычно лучше объяснить решение, а не просто опубликовать несколько строк анонимного кода. Вы можете прочитать Как написать хороший ответ , а также Объяснить полностью основанные на коде ответы .
Массимилиано Краус
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.