Utworzyłem tablicę z ukośną krawędzią, używając dwóch pętli for, ale zastanawiam się, czy jest na to prostszy sposób, na przykład z listą składaną:

im_diag = np.zeros((im_size, im_size), dtype=np.int8)

for x in range(im_size):
    for y in range(im_size):
        if x+y >= im_size:
            im_diag[x,y] = 1

Wyjście (im_size = 5):

>>> im_size
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1],
       [0, 0, 0, 1, 1],
       [0, 0, 1, 1, 1],
       [0, 1, 1, 1, 1]], dtype=int8)
2
Schneekind 20 listopad 2019, 17:06

3 odpowiedzi

Ogólnie rzecz biorąc, używając numpy, o wiele lepiej jest użyć metody wektorowej, która stanie się o wiele szybsza niż metody wykorzystujące pętle i listy składane wraz ze wzrostem rozmiaru pożądanej tablicy.

>>> np.flip(np.tril(np.ones((5,5)), k=-1), 1)
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 1.],
       [0., 0., 0., 1., 1.],
       [0., 0., 1., 1., 1.],
       [0., 1., 1., 1., 1.]])

np.ones, aby utworzyć tablicę 1s,

np.tril, aby utworzyć dolną tablicę trójkątną

np.flip, aby odwrócić tablicę w poziomie

Porównanie czasu z innymi odpowiedziami:

enter image description here

Jak pokazano, z n>=10, metoda numpy jest szybsza, a gdy n staje się większe, ta metoda będzie około 10 razy szybsza niż rozwiązania ze zrozumieniem list.

Kod do odtworzenia:

import perfplot
import numpy as np

def cdjb(n):
    return np.flip(np.tril(np.ones((n,n)), k=-1), 1)

def displayname(n):
    return [[int(j > i) for j in range(n)] for i in range(n)][::-1]

def MikeMajara(n):
    return [[1 if i+j >= n else 0 for i in range(n)] for j in range(n)]

perfplot.show(
    setup=lambda n: n,
    n_range=[2**k for k in range(14)],
    kernels=[
        cdjb,displayname,MikeMajara
        ],
    xlabel='Size of Array',
    )
5
CDJB 13 luty 2020, 10:31
W takim razie powiedziałbym, że to powinno być częścią twojej odpowiedzi. Nie ma oczywistego sposobu, aby powiedzieć na pierwszy rzut oka (szczególnie dla uczniów). Powiedziałbym również, że wadą jest czytelność, ponieważ nigdzie w pytaniu nie wspomniano o wydajności ani o dużych wymiarach tablicy, ale nadal zaawansowane funkcje biblioteki są używane i powiązane z nimi. Z tego powodu, IMHO, najlepszym podejściem jest stanowisko PO, chyba że w grę wchodzi wydajność.
 – 
MikeMajara
20 listopad 2019, 17:27
Dodałem wykres porównania czasu. Twoje rozwiązanie do rozumienia listy jest szybsze niż drugie, (+1), ale numpy nadal będzie bić oba dla n większych niż 10.
 – 
CDJB
10 luty 2020, 11:56

Jeśli szukałeś listy ze zrozumieniem, może to być twoje rozwiązanie:

[[1 if i+j >= im_size else 0 for i in range(im_size)] for j in range(im_size)]

Ale złożone listy ze zrozumieniem są trudniejsze do odczytania / zrozumienia. A nieczytelny kod nie jest pythonowy. Więc pomyśl o tym.

1
CDJB 10 luty 2020, 21:20

Ze zrozumieniem listy (nie numpy wymagane):

n = 5
[[int(j > i) for j in range(n)] for i in range(n)][::-1]

Daje

[[0, 0, 0, 0, 0],
 [0, 0, 0, 0, 1],
 [0, 0, 0, 1, 1],
 [0, 0, 1, 1, 1],
 [0, 1, 1, 1, 1]]

Gdzie [::-1] po prostu odwraca zewnętrzną listę.

2
Stefan Falk 20 listopad 2019, 17:21