Two-dimensional lists (arrays) - Learn Python 3 - Snakify

Lesson 9
İki boyutlu listeler (diziler)


1. İç içe geçmiş listeler: işleme ve yazdırma

Gerçek dünyada Çok sayıda görev, dikdörtgen veri tablosunu saklamak zorundadır. [bu konuda daha fazlasını söyle!] Bu tablolara matrisler veya iki boyutlu diziler denir. Python'da herhangi bir tablo bir liste listesi olarak (her öğenin sırayla bir liste olduğu bir liste) temsil edilebilir. Örneğin, burada iki satır ve üç sütun içeren sayısal bir tablo oluşturan ve daha sonra bazı manipülasyonlar yapan program:
a = [[1, 2, 3], [4, 5, 6]]
print(a[0])
print(a[1])
b = a[0]
print(b)
print(a[0][2])
a[0][1] = 7
print(a)
print(b)
b[2] = 9
print(a[0])
print(b)

Birinci eleman a - burada a[0] - numaralarının listesi [1, 2, 3] . Bu yeni listenin ilk elemanı a[0][0] == 1 ; dahası, a[0][1] == 2 , a[0][2] == 3 , a[1][0] == 4 , a[1][1] == 5 , a[1][2] == 6 .

2 boyutlu diziyi işlemek için genellikle yuvalanmış döngüler kullanırsınız. Birinci döngü, satır numarası boyunca yinelenir, ikinci döngü, bir satırın içindeki elemanlar boyunca ilerler. Örneğin, ekran satırında iki boyutlu sayısal listeyi böylelikle satırlarla ayırarak, bu şekilde sırayla görüntülersiniz:

a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]]
for i in range(len(a)):
    for j in range(len(a[i])):
        print(a[i][j], end=' ')
    print()

Python'daki bir for döngüsü değişkeninin sadece bir range() üzerinde değil, genellikle herhangi bir dizinin tüm öğeleri üzerinde yinelemediğini açıklamaya çalıştık. Python'daki diziler, listeler ve dizelerdir (ve henüz tanışmadığımız diğer nesneler). Eğer döngü bu kullanışlı özelliğini kullanarak, iki boyutlu bir dizi yazdırabilirsiniz Bak nasıl for :

a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]]
for row in a:
    for elem in row:
        print(elem, end=' ')
    print()

Doğal olarak, tek bir satır çıktılamak için method join() yöntemini kullanabilirsiniz:

for row in a:
    print(' '.join([str(elem) for elem in row]))

2 boyutlu listeden tüm sayıların toplamını hesaplamak için 2 yuvalanmış döngüyü kullanabilirsiniz:

a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]]
s = 0
for i in range(len(a)):
    for j in range(len(a[i])):
        s += a[i][j]
print(s)

Ya da i ve j değişkenleri tarafından değil, elemanlarla yinelenen ile aynı:

a = [[1, 2, 3, 4], [5, 6], [7, 8, 9]]
s = 0
for row in a:
    for elem in row:
        s += elem
print(s)
Advertising by Google, may be based on your interests

2. İç içe geçmiş listeler: oluşturma

İki sayının verildiğini varsayalım: n satır sayısı ve sütun sayısı m . Sıfırla doldurulan n × m boyutunda bir liste oluşturmalısınız.

Açık çözüm yanlış görünüyor:

a = [[0] * m] * n

Bu, a[0][0] nın değerini 5 ayarlarsanız ve sonra a[1][0] değerini basarsanız kolayca görülebilir. Bu aynı zamanda 5'e eşit olacaktır. Nedeni, [0] * m , yalnızca bir m sıfır listesi için bir başvuru döndürür, ancak bir liste değildir. Bu elemanın müteakip tekrarı, aynı listeye atıfta bulunan n maddelerinin bir listesini oluşturur (aynı zamanda, işlem b = a listeleri için yeni listeyi oluşturmaz), böylece sonuç listesindeki tüm satırlar aslında aynıdır. dize.

Görselleştiricimizi kullanarak listelerin kimliğini takip edin. İki liste aynı kimlik numarasına sahipse, aslında bellekte aynı liste.

n = 3
m = 4
a = [[0] * m] * n
a[0][0] = 5
print(a[1][0])

Böylece, iki boyutlu bir liste sadece bir dizgeyi tekrarlayarak oluşturulamaz. Ne yapalım?..

Olası bir yol: Eğer bir liste oluşturabilir n (söyledikleriyle, elementlerin n sıfır) ve daha sonra diğer öğelerden biri boyutlu listesine bir bağlantı her yapmak m elemanları:

n = 3
m = 4
a = [0] * n
for i in range(n):
    a[i] = [0] * m

Başka (ama benzer) bir yol: boş bir liste oluşturun ve n kez yeni bir eleman append (bu eleman m uzunluğunun bir listesi olmalıdır):

n = 3
m = 4
a = []
for i in range(n):
    a.append([0] * m)

Ancak en kolay yol, her biri m sıfır sayısı olan n öğelerinin bir listesini oluşturarak jeneratörü kullanmaktır:

n = 3
m = 4
a = [[0] * m for i in range(n)]

Bu durumda, her eleman diğerlerinden bağımsız olarak oluşturulur. [0] * m listesi n yeni zaman olarak oluşturulur ve referansların kopyalanması gerçekleşmez.

Advertising by Google, may be based on your interests

3. İki boyutlu bir diziyi nasıl girersiniz?

Bir program, her biri boşluklarla ayrılmış m sayıları içeren n satırları şeklinde iki boyutlu diziyi girer. Programı okumak için nasıl zorlarsınız? Bunu nasıl yapabileceğinize bir örnek:

# İlk giriş satırı dizinin satır sayısıdır
n = int(input()) 
a = []
for i in range(n):
    a.append([int(j) for j in input().split()])

Ya da sofistike iç içe aramalar kullanmadan:

# İlk giriş satırı dizinin satır sayısıdır
n = int(input()) 
a = []
for i in range(n):
    row = input().split()
    for i in range(len(row)):
        row[i] = int(row[i])
    a.append(row)

Jeneratörlerle aynısını yapabilirsiniz:

# İlk giriş satırı dizinin satır sayısıdır
n = int(input()) 
a = [[int(j) for j in input().split()] for i in range(n)]
Advertising by Google, may be based on your interests

4. İki boyutlu bir dizinin işlenmesi: bir örnek

Bir kare dizi ( n satır ve n sütun dizisi) verildiğini varsayalım. Ve ana köşegen elemanların 1'e eşit olması gerektiğini varsayalım (yani, a[i][j] için i==j olan bu elemanlar, o diyagonalin 0'a eşit olandan ötesine ayarlanması ve elemanların ayarlanmasıdır. Bu diyagonalin 2 altına eşittir. Yani, böyle bir dizi oluşturmanız gerekir (örnek n==4 ):

 
1 0 0 0
2 1 0 0
2 2 1 0
2 2 2 1
(Bu durumda, a[0][0] = 1 , a[0][1] = 0 vb. Ayarlayarak bunu manuel olarak yapabilirsiniz, ancak 100 satır ve 100 sütun dizisi için el ile yapmazsınız. çoğu zaman durum böyle.)

Bu sorunu çözmenin birkaç yolunu göstermek için sabırsızlanıyoruz. Unsurlardır - İlk olarak, ana diyagonal üzerinde bulunan elemanlar dikkat a[i][j] olan i<j ana diyagonal aşağıdaki elemanları ve bu i>j . Böylece, a[i][j] nin değerini belirleyen i ve j değerlerini karşılaştırabiliriz. Aşağıdaki algoritmayı alıyoruz:

n = 4
a = [[0] * n for i in range(n)]
for i in range(n):
    for j in range(n):
        if i < j:
            a[i][j] = 0
        elif i > j:
            a[i][j] = 2
        else:
            a[i][j] = 1
for row in a:
    print(' '.join([str(elem) for elem in row]))

Bu algoritma yavaştır: iki döngü kullanır ve her çift için (i,j) yönergeler if bir veya iki yürütür. Eğer algoritmayı karmaşıklaştırırsak, şartlı bir açıklama yapmadan bunu yapabiliriz.

İlk olarak, bir döngüye ihtiyacımız olan ana köşegeni doldurun:

for i in range(n):
    a[i][i] = 1

Ardından, ana diyagonalin üzerindeki tüm elemanları sıfırlarla doldurun. Numarası ile her satır için, bu hale getirmek için i size bir değer atamak için gereken a[i][j] için j = i+1 , ..., n-1 . Bunu yapmak için iç içe döngülere ihtiyacınız var:

for i in range(n):
    for j in range(i + 1, n):
        a[i][j] = 0

Benzer şekilde j = 0 , ... için, i-1 elemanları a[i][j] 2 eşit olarak ayarlar:

for i in range(n):
    for j in range(0, i):
        a[i][j] = 2

Tüm bu kodu birleştirebilir ve başka bir çözüm alabilirsiniz:

n = 4
a = [[0] * n for i in range(n)]
for i in range(n):
    for j in range(0, i):
        a[i][j] = 2
    a[i][i] = 1
    for j in range(i + 1, n):
        a[i][j] = 0
for row in a:
    print(' '.join([str(elem) for elem in row]))

Listenin bir sonraki satırlarını oluşturmak için listeleri tekrarlayan başka bir çözüm. Listenin i hattı i 2 rakamı, ardından 1 tam sayı, 1 ni-1 sıfırdan oluşur.

n = 4
a = [0] * n
for i in range(n):
    a[i] = [2] * i + [1] + [0] * (n - i - 1)
for row in a:
    print(' '.join([str(elem) for elem in row]))    

Her zaman olduğu gibi, döngüyü jeneratörle değiştirebilirsiniz:

n = 4
a = [0] * n
a = [[2] * i + [1] + [0] * (n - i - 1) for i in range(n)]
for row in a:
    print(' '.join([str(elem) for elem in row]))    
Advertising by Google, may be based on your interests

5. İki boyutlu diziler: iç içe jeneratörler

İki boyutlu diziler oluşturmak için iç içe jeneratörler kullanabilir, bir dizge olan listenin jeneratörünü tüm dizelerin oluşturucusunun içine yerleştirebilirsiniz. Jeneratörü kullanarak n satır ve m sütunların bir listesini oluşturabileceğinizi hatırlayın (bu, her elemanın m sıfırlar listesi olduğu n öğelerinin bir listesini oluşturur):

[[0] * m for i in range(n)]

Ancak iç liste, örneğin, bu tür bir jeneratör kullanılarak da oluşturulabilir: [0 for j in range(m)] . Bir jeneratörü diğerine yerleştirmek, elde ederiz

[[0 for j in range(m)] for i in range(n)]

Sorunumuzla nasıl bağlantılı? Sorun şu ki, 0 sayısı i (satır numarası) ve j (sütun numarası) bağlı olan bir ifadeyle değiştirilirse, matrisin bazı formüllere göre doldurulur.

Örneğin, aşağıdaki diziyi başlatmanız gerektiğini varsayalım (kolaylık için, öğeler arasında ekstra boşluklar eklenir):

0  0  0  0  0  0
0  1  2  3  4  5
0  2  4  6  8 10
0  3  6  9 12 15
0  4  8 12 16 20

Bu dizide n = 5 satır, m = 6 sütun vardır ve satır indeksi i ve sütun dizini j olan öğe, a[i][j] = i * j formülüyle hesaplanır.

Her zaman olduğu gibi, böyle bir dizi oluşturmak için jeneratörü kullanabilirsiniz:

[[i * j for j in range(m)] for i in range(n)]
Advertising by Google, may be based on your interests