Làm cách nào để khởi tạo một mảng hai chiều trong Python?


262

Tôi đang bắt đầu python và tôi đang cố gắng sử dụng một danh sách hai chiều, ban đầu tôi điền vào cùng một biến ở mọi nơi. Tôi nghĩ ra cái này:

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

Nó cho kết quả mong muốn, nhưng cảm thấy như một cách giải quyết. Có một cách dễ dàng hơn / ngắn hơn / thanh lịch hơn để làm điều này?


7
Chỉ là một số nhỏ (hoặc đáng kể, tùy thuộc vào người đang xem) nitpick: danh sách không phải là mảng. Nếu bạn muốn mảng, sử dụng numpy.
Arnab Datta

Câu hỏi này tương tự : nó thảo luận về việc khởi tạo các mảng nhiều chiều trong Python.
Anderson Green

@ArnabDatta Làm thế nào bạn sẽ khởi tạo một mảng nhiều chiều trong numpy, sau đó?
Anderson Green


Bạn có thể sắp xếp dữ liệu trong một mảng như cấu trúc trong Python mặc định nhưng nó gần như không hiệu quả hoặc hữu ích như mảng NumPy. Đặc biệt nếu bạn muốn đối phó với các tập dữ liệu lớn. Dưới đây là một số tài liệu docs.scipy.org/doc/numpy-1.10.1/user/basics.creation.html
jmdeamer

Câu trả lời:


376

Một mô hình thường xuất hiện trong Python là

bar = []
for item in some_iterable:
    bar.append(SOME EXPRESSION)

đã giúp thúc đẩy việc giới thiệu danh sách, giúp chuyển đổi đoạn mã đó thành

bar = [SOME EXPRESSION for item in some_iterable]

đó là ngắn hơn và đôi khi rõ ràng hơn. Thông thường bạn có thói quen nhận ra những điều này và thường thay thế các vòng lặp bằng sự hiểu biết.

Mã của bạn theo mẫu này hai lần

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
Nhân tiện, [[foo] * 10 cho x in xrange (10)] có thể được sử dụng để thoát khỏi một sự hiểu biết. Vấn đề là phép nhân thực hiện một bản sao nông, vì vậy new = [foo] * 10 new = [new] * 10 sẽ giúp bạn có một danh sách chứa cùng một danh sách mười lần.
Scott Wolchok

8
Tương tự, [foo] * 10là một danh sách có cùng foo10 lần chính xác , có thể hoặc không quan trọng.
Mike Graham

2
chúng ta có thể sử dụng điều đơn giản nhất: wtod_list = [[0 cho x in xrange (10))] cho x in xrange (10)]
indi60

2
Mặc dù vậy, nó không bao giờ đau đớn để cho ai đó thấy một con cá trông như thế nào.
Csteele5

2
Đối với nhận xét của Mike Graham về [foo] * 10: Điều này có nghĩa là điều này sẽ không hoạt động nếu bạn điền vào một mảng bằng các số ngẫu nhiên ( [random.randint(1,2)] * 10ước tính [1] * 10hoặc [2] * 10có nghĩa là bạn nhận được một mảng của tất cả 1 hoặc 2, thay vì một mảng ngẫu nhiên.
Tzu Li

224

Bạn có thể sử dụng một danh sách hiểu :

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
vì kích thước (10) giống nhau, nên nếu không phải vòng lặp lồng nhau phải đến trước [foo cho j trong phạm vi (phạm vi_of_j)] cho i trong phạm vi (phạm vi_of_i)]
Dineshkumar 28/03/2015

2
Câu trả lời này hoạt động tốt nhưng tôi vì chúng tôi lặp lại icho các hàng và jcho các cột, tôi nghĩ nên trao đổi ijtheo cú pháp của bạn để hiểu rõ hơn và thay đổi phạm vi thành 2 số khác nhau.
DragonKnight

138

Cách này nhanh hơn cách hiểu danh sách lồng nhau

[x[:] for x in [[foo] * 10] * 10]    # for immutable foo!

Dưới đây là một số thời gian python3, cho danh sách nhỏ và lớn

$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

Giải trình:

[[foo]*10]*10tạo một danh sách của cùng một đối tượng được lặp lại 10 lần. Bạn không thể chỉ sử dụng điều này, bởi vì sửa đổi một yếu tố sẽ sửa đổi cùng một yếu tố đó trong mỗi hàng!

x[:]tương đương list(X)nhưng hiệu quả hơn một chút vì nó tránh được việc tra cứu tên. Dù bằng cách nào, nó tạo ra một bản sao nông của mỗi hàng, vì vậy bây giờ tất cả các yếu tố là độc lập.

Tất cả các yếu tố là cùng một foođối tượng, vì vậy nếu foocó thể thay đổi , bạn không thể sử dụng lược đồ này., Bạn phải sử dụng

import copy
[[copy.deepcopy(foo) for x in range(10)] for y in range(10)]

hoặc giả sử một lớp (hoặc hàm) Footrả về foos

[[Foo() for x in range(10)] for y in range(10)]

4
@Mike, bạn có bỏ lỡ phần in đậm không? nếu foo có thể thay đổi, không có câu trả lời nào khác ở đây hoạt động (trừ khi bạn không biến đổi foo chút nào)
John La Rooy

1
Bạn không thể sao chép chính xác các đối tượng tùy ý bằng cách sử dụng copy.deepcopy. Bạn cần một kế hoạch cụ thể cho dữ liệu của bạn nếu bạn có một đối tượng có thể thay đổi tùy ý.
Mike Graham

1
Nếu bạn cần tốc độ quá tệ trong một vòng lặp, có lẽ đã đến lúc sử dụng Cython, dệt hoặc tương tự ...
james.haggerty

1
@JohnLaRooy tôi nghĩ bạn đã thay thế xy. Không nên như vậy[[copy.deepcopy(foo) for y in range(10)] for x in range(10)]
user3085931

1
@Nils [foo]*10không tạo ra 10 đối tượng khác nhau - nhưng thật dễ dàng bỏ qua sự khác biệt trong trường hợp foo là bất biến, như một inthoặc str.
John La Rooy

137

Đừng sử dụng [[v]*n]*n, đó là một cái bẫy!

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

nhưng

    t = [ [0]*3 for i in range(3)]

làm việc tuyệt vời


26
vâng, tôi cũng rơi vào cái bẫy này Đó là bởi vì *đang sao chép addressđối tượng (danh sách).
chinuy

1
Nâng cao, vì điều này có tôi. Để rõ ràng hơn , [[0] * col for _ in range(row)].
Abhijit Sarkar

62

Để khởi tạo một mảng hai chiều trong Python:

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

4
Để khởi tạo tất cả các giá trị về 0, chỉ cần sử dụng 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 () đã bị xóa trong python3.5
MiaeKim

tại sao điều này không hoạt động: [0 * col] * hàng. Khi tôi sửa đổi một số phần tử, nó sao chép ở những nơi khác. Nhưng tôi không hiểu tại sao?
mã muncher

Bởi vì điều đó thực hiện chính xác giống như mã trong câu hỏi.
Ignacio Vazquez-Abrams

2
@codemuncher Lý do [[0] * col] * rowkhông làm những gì bạn muốn là vì khi bạn khởi tạo danh sách 2d theo cách đó, Python sẽ không tạo các bản sao riêng biệt của mỗi hàng. Thay vào đó, nó sẽ khởi tạo danh sách bên ngoài với các con trỏ tới cùng một bản sao của [0]*col. Bất kỳ chỉnh sửa nào bạn thực hiện cho một trong các hàng sau đó sẽ được phản ánh trong các hàng còn lại vì tất cả chúng đều thực sự trỏ đến cùng một dữ liệu trong bộ nhớ.
Addie

Chỉ là một suy nghĩ nhưng không phải tất cả các danh sách này không tốt cho việc nối thêm? I E. nếu tôi muốn một danh sách 2D trống có kích thước 3 * 6 và muốn thêm vào chỉ mục [0] [0], [1] [0], [2] [0] và cứ thế lấp đầy tất cả 18 yếu tố, không có yếu tố nào Những câu trả lời này sẽ hoạt động phải không?
mLstudent33

22

Thông thường khi bạn muốn các mảng nhiều chiều, bạn không muốn có một danh sách các danh sách, mà là một mảng khó hiểu hoặc có thể là một lệnh.

Ví dụ, với numpy bạn sẽ làm một cái gì đó như

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

2
Mặc dù numpylà tuyệt vời, tôi nghĩ rằng nó có thể là một chút quá mức cho người mới bắt đầu.
Esteban Küber

3
numpy cung cấp một loại mảng đa chiều. Xây dựng một mảng đa chiều tốt trong danh sách là có thể nhưng ít hữu ích và khó hơn cho người mới bắt đầu so với sử dụng numpy. Danh sách lồng nhau rất tốt cho một số ứng dụng, nhưng thường thì những gì mà ai đó muốn có mảng 2d sẽ tốt nhất.
Mike Graham

1
sau một vài năm thỉnh thoảng thực hiện các ứng dụng python nghiêm trọng, các quirks của mảng python tiêu chuẩn dường như sẽ được bảo đảm numpy. +1
javadba

12

Bạn có thể làm điều này:

[[element] * numcols] * numrows

Ví dụ:

>>> [['a'] *3] * 2
[['a', 'a', 'a'], ['a', 'a', 'a']]

Nhưng điều này có tác dụng phụ không mong muốn:

>>> 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
Theo kinh nghiệm của tôi, hiệu ứng "không mong muốn" này thường là nguồn gốc của một số lỗi logic rất xấu. Theo tôi, nên tránh cách tiếp cận này, thay vào đó câu trả lời của @ Vipul tốt hơn nhiều.
Alan Turing

Cách tiếp cận này hoạt động tốt, tại sao trong ý kiến ​​một số người cho rằng nó là xấu?
Bravo

1
Do tác dụng phụ không mong muốn, bạn thực sự không thể coi nó như một ma trận. Nếu bạn không cần thay đổi nội dung thì mọi chuyện sẽ ổn thôi.
hithwen

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

với n là số hàng và m là số cột và foo là giá trị.


8

Nếu đó là một mảng dân cư thưa thớt, bạn có thể tốt hơn bằng cách sử dụng một từ điển được khóa với một tuple:

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

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

đối với mỗi phần tử, một phần tử mới [0]*10sẽ được tạo ..


4

Cách tiếp cận không chính xác: [[Không * 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

Với phương pháp này, python không cho phép tạo không gian địa chỉ khác nhau cho các cột bên ngoài và sẽ dẫn đến nhiều hành vi sai trái hơn mong đợi của bạn.

Cách tiếp cận đúng nhưng ngoại lệ:

y = [[0 for i in range(m)] for j in range(n)]
>>> id(y[0][0]) == id(y[1][0])
False

Đó là cách tiếp cận tốt nhưng có ngoại lệ nếu bạn đặt giá trị mặc định thành 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

Vì vậy, đặt giá trị mặc định của bạn đúng cách sử dụng phương pháp này.

Hoàn toàn chính xác:

Thực hiện theo câu trả lời của mike của vòng lặp đôi .


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

1
Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do và / hoặc cách mã này trả lời câu hỏi cải thiện giá trị lâu dài của nó.
Ajean

3

Để khởi tạo mảng 2 chiều, hãy sử dụng: arr = [[]*m for i in range(n)]

thực ra, arr = [[]*m]*n sẽ tạo ra một mảng 2D trong đó tất cả các mảng n sẽ trỏ đến cùng một mảng, do đó, mọi thay đổi về giá trị trong bất kỳ phần tử nào sẽ được phản ánh trong tất cả các danh sách n

để được giải thích thêm, hãy truy cập: https://www.geekforgeek.org/python-USE-2d-arrays-lists-the-right-way/


3

sử dụng suy nghĩ đơn giản nhất để tạo ra điều này.

wtod_list = []

và thêm kích thước:

wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]

hoặc nếu chúng ta muốn khai báo kích thước trước tiên. chúng tôi chỉ sử dụng:

   wtod_list = [[0 for x in xrange(10)] for x in xrange(10)]

1

Như @Arnab và @Mike đã chỉ ra, một mảng không phải là một danh sách. Một số khác biệt là 1) mảng có kích thước cố định trong quá trình khởi tạo 2) mảng thường hỗ trợ các hoạt động ít hơn so với danh sách.

Có thể là quá mức trong hầu hết các trường hợp, nhưng đây là cách triển khai mảng 2d cơ bản, thúc đẩy triển khai mảng phần cứng bằng cách sử dụng python ctypes (thư viện 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

Điều quan trọng tôi hiểu là: Trong khi khởi tạo một mảng (ở bất kỳ chiều nào) Chúng ta nên đưa ra một giá trị mặc định cho tất cả các vị trí của mảng. Sau đó, chỉ khởi tạo hoàn thành. Sau đó, chúng ta có thể thay đổi hoặc nhận các giá trị mới cho bất kỳ vị trí nào của mảng. Các mã dưới đây làm việc cho tôi hoàn hảo

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

Nếu bạn sử dụng numpy , bạn có thể dễ dàng tạo các mảng 2d:

import numpy as np

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

x

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

Ở trên sẽ cung cấp cho bạn một mảng 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]]

Đó là sử dụng sự hiểu biết danh sách lồng nhau. Phân tích như sau:

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

[x] * col -> biểu thức cuối cùng được ước tính
cho x in -> x sẽ là giá trị được cung cấp bởi iterator
[b cho b trong phạm vi (hàng)]] -> Iterator.

[b cho b trong phạm vi (hàng)]] điều này sẽ ước tính thành [0,1,2,3,4] vì hàng = 5
nên giờ nó đơn giản hóa thành

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

Điều này sẽ ước tính thành [[0] * 5 cho x trong [0,1,2,3,4]] -> với x = 0 lần lặp đầu tiên
[[1] * 5 cho x trong [0,1,2, 3,4]] -> với x = 1 lần lặp thứ 2
[[2] * 5 cho x trong [0,1,2,3,4]] -> với x = 2 lần lặp thứ 3
[[3] * 5 cho x trong [0,1,2,3,4]] -> với x = 3 lần lặp thứ 4
[[4] * 5 cho x trong [0,1,2,3,4]] -> với x = 4 lần lặp thứ 5


0

Đây là cách tốt nhất tôi tìm thấy để dạy lập trình viên mới và không sử dụng các thư viện bổ sung. Tôi muốn một cái gì đó tốt hơn mặc dù.

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

0

Đây là một cách dễ dàng hơn:

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

Để khởi tạo tất cả các ô với bất kỳ giá trị 'x' nào, hãy sử dụng:

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

0

Thường thì tôi sử dụng phương pháp này để khởi tạo mảng 2 chiều

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


0

Mẫu chung để thêm kích thước có thể được rút ra từ loạt bài này:

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)

Chào mừng đến với SO. Câu hỏi này đã có một câu trả lời được chấp nhận ồ ạt. Ngay từ cái nhìn đầu tiên, bài viết này không thực sự trả lời câu hỏi. Xem stackoverflow.com/help/how-to-answer để được hướng dẫn.
Nick

0

Bạn có thể thử điều này [[0] * 10] * 10. Điều này sẽ trả về mảng 2d gồm 10 hàng và 10 cột có giá trị 0 cho mỗi ô.


Đây thực chất là câu trả lời tương tự như stackoverflow.com/a/25601284/2413201 ...
Armali

2
Điều này tạo ra mảng 10 con trỏ đến cùng một hàng. Nếu bạn làm a = [[0]*10]*10và sau đó a[0][0] = 1bạn sẽ thấy phần tử đầu tiên trong mỗi hàng bây giờ bằng 1
andnik

0

lst = [[0] * m cho i trong phạm vi (n)]

khởi tạo tất cả ma trận n = hàng và m = cột


Bạn có thể vui lòng định dạng mã dưới dạng mã? Nó sẽ là cách dễ đọc hơn.
Thomas

0

Một cách khác là sử dụng từ điển để giữ một mảng hai chiều.

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

Điều này chỉ có thể giữ bất kỳ giá trị 1D, 2D nào và để khởi tạo giá trị này thành 0hoặc bất kỳ giá trị int nào khác, hãy sử dụng các bộ sưu tập .

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

0

Mã số:

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 phải bất biến.


-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
Vui lòng thêm một số văn bản mô tả những gì mã của bạn làm.
whackamadoodle3000

1
Thông thường tốt hơn là giải thích một giải pháp thay vì chỉ đăng một số hàng mã ẩn danh. Bạn có thể đọc Làm thế nào để tôi viết một câu trả lời hay và cũng Giải thích các câu trả lời hoàn toàn dựa trên mã .
Massimiliano Kraus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.