Як ініціалізувати двовимірний масив у 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
Просто невелика (або значна, залежно від того, хто дивиться) nitpick: списки не є масивами. Якщо ви хочете масиви, використовуйте 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 in xrange (10)] можна використовувати для позбавлення від одного розуміння. Проблема полягає в тому, що множення робить дрібну копію, тому new = [foo] * 10 new = [new] * 10 отримає вам список, що містить той самий список десять разів.
Скотт Волчок

8
Аналогічно [foo] * 10- це список з таким самим точним foo10 разів, який може бути або не бути важливим.
Майк Грехем

2
ми можемо використати найпростішу річ: wtod_list = [[0 для x у xrange (10))] для x in xrange (10)]
indi60

2
Ніколи не зашкодить показати комусь, що схожа на рибу.
Csteele5

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

224

Ви можете використати розуміння списку :

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 for j in range (range_of_j)] для i in range (range_of_i)]
Dineshkumar,

2
Ця відповідь прекрасно працює, але, оскільки ми повторюємо iрядки та jстовпці, я думаю, що для кращого розуміння та зміни діапазону на 2 різні числа слід вважати, що краще замінити iі jу вашому синтаксисі.
DragonKnight

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
@Mike, ти пропустив твір жирним шрифтом? якщо foo є змінним, жодна з інших відповідей тут не працює (якщо ви зовсім не мутуєте foo)
Джон Ла Руй,

1
Ви не можете правильно скопіювати довільні об’єкти за допомогою copy.deepcopy. Вам потрібен план, специфічний для ваших даних, якщо у вас є довільний об'єкт, що змінюється.
Майк Грехем

1
Якщо вам потрібна швидкість, яка погано перебуває в циклі, можливо, настав час використовувати Cython, ткати або подібне ...
james.haggerty

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

1
@Nils [foo]*10не створює 10 різних об'єктів - але легко не помітити різницю у випадку, коли foo є незмінним, як, наприклад, intабо str.
Джон Ла Рой

137

Не використовуйте [[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об'єкта (списку).
chinuy

1
Оголошений, оскільки мене це дістало. Щоб бути більш ясним, [[0] * col for _ in range(row)].
Абхіджіт Саркар

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] * рядок. Коли я змінюю якийсь елемент, він реплікується в інших місцях. Але я не розумію, чому?
кодовий манчер

Тому що це робить те саме, що і код у питанні.
Ігнасіо Васкес-Абрамс

2
@codemuncher Причина, [[0] * col] * rowяка не робить те, що ви хочете, полягає в тому, що коли ви ініціалізуєте 2d список таким чином, Python не створюватиме чіткі копії кожного рядка. Натомість він запустить зовнішній список із вказівниками на ту ж копію [0]*col. Будь-яке внесення змін до одного з рядків буде відображено в решти рядків, оскільки вони фактично вказують на ті самі дані в пам'яті.
Адді

Просто думка, але чи не всі ці списки корисні для додавання? Тобто якщо я хочу порожній двовимірний список розмірності 3 * 6 і хочу додати до індексу [0] [0], [1] [0], [2] [0] і так далі, щоб заповнити всі 18 елементів, жоден з ці відповіді спрацюють правильно?
mLstudent33

22

Зазвичай, коли ви хочете багатовимірних масивів, вам не потрібен список списків, а скоріше нумерований масив або, можливо, диктант.

Наприклад, з numpy ви зробили б щось подібне

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

2
Хоча numpyце чудово, я думаю, що це може бути трохи зайвим для початківця.
Естебан Кюбер

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

1
через кілька років періодично роблячи серйозні додатки python, здається, вигадки стандартних масивів пітонів як раз вимагають того, щоб продовжувати numpy. +1
javadba

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


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

Для ініціалізації двовимірного масиву використовуйте: 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 (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 у діапазоні (рядок)]] -> Ітератор.

[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] * 5 для x в [0,1,2,3,4]] -> з x = 3 четверта ітерація
[[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

Часто я використовую такий підхід для ініціалізації двовимірного масиву

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)

Ласкаво просимо до SO. На це запитання вже є прийнята відповідь масово. На перший погляд, ця публікація насправді не відповідає на питання. Докладні відомості див. У розділі 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.