2009-02-03 4 views
8

Ho un piccolo problema Java che voglio tradurre in Python. Perciò ho bisogno di un array multidimensionale. In Java appare come:Matrice multidimensionale in Python

double dArray[][][] = new double[x.length()+1][y.length()+1][x.length()+y.length()+3]; 
dArray[0][0][0] = 0; 
dArray[0][0][1] = POSITIVE_INFINITY; 

Altri valori verranno creati in cicli e scritti nell'array.

Come si istanzia l'array?

PS: Non v'è alcuna moltiplicazione di matrici coinvolte ...

+0

Per inciso, è possibile ottenere l'infinito in virgola mobile in python come' float ('inf') '. Si comporta più o meno come ci si aspetterebbe: la maggior parte delle operazioni ti dà solo inf e alcuni ti danno nan. –

+0

(unito a una domanda precedente, mantenuto come master come: l'OP esiste ancora, b: la domanda è meglio formulata, e c: per evitare molti negromanti) –

risposta

11

È possibile creare utilizzando elenchi nidificati:

matrix = [[a,b],[c,d],[e,f]] 

Se deve essere dinamico è più complicato, perché non scrivere una piccola classe te stesso?

class Matrix(object): 
    def __init__(self, rows, columns, default=0): 
     self.m = [] 
     for i in range(rows): 
      self.m.append([default for j in range(columns)]) 

    def __getitem__(self, index): 
     return self.m[index] 

Questo può essere utilizzato in questo modo:

m = Matrix(10,5) 
m[3][6] = 7 
print m[3][6] // -> 7 

sono sicuro che si potrebbe implementare lo considerano più efficace. :)

Se sono necessari array multidimensionali, è possibile creare una matrice e calcolare l'offset oppure utilizzare array in matrici di array, il che può essere piuttosto negativo per la memoria.(Potrebbe essere più veloce anche se ...) ho implementato la prima idea in questo modo:

class Matrix(object): 
    def __init__(self, *dims): 
     self._shortcuts = [i for i in self._create_shortcuts(dims)] 
     self._li = [None] * (self._shortcuts.pop()) 
     self._shortcuts.reverse() 

    def _create_shortcuts(self, dims): 
     dimList = list(dims) 
     dimList.reverse() 
     number = 1 
     yield 1 
     for i in dimList: 
      number *= i 
      yield number 

    def _flat_index(self, index): 
     if len(index) != len(self._shortcuts): 
      raise TypeError() 

     flatIndex = 0 
     for i, num in enumerate(index): 
      flatIndex += num * self._shortcuts[i] 
     return flatIndex 

    def __getitem__(self, index): 
     return self._li[self._flat_index(index)] 

    def __setitem__(self, index, value): 
     self._li[self._flat_index(index)] = value 

Può essere usato in questo modo:

m = Matrix(4,5,2,6) 
m[2,3,1,3] = 'x' 
m[2,3,1,3] // -> 'x' 
3

per i dati numerici, Numpy Arrays:

>>> matrix1 = array(([0,1],[1,3])) 
>>> print matrix1 
[[0 1] 
[1 3]] 

Per i dati generali (ad esempio stringhe), è possibile utilizzare una lista di liste, la lista dei tuple, ...

matrix2 = [['a','b'], ['x','y']] 
+0

Posso inizializzare un certo numero di righe e colonne come in C? –

+0

Gli oggetti mutabili (ad es. Elenco) possono essere modificati, pertanto l'inizializzazione non è sempre pertinente. In numpy, una matrice ha una forma (dimensioni) che può essere modificata senza modificare i dati. – gimel

+1

@Popper: Sì. zeros ((3,4)) creerà una matrice 3x4 di zeri. –

18

Se ti limitare alla libreria standard di Python, quindi una lista di liste è il costrutto più vicina:

arr = [[1,2],[3,4]] 

fornisce una matrice tipo 2D. Le righe sono accessibili come arr[i] per i in {0,..,len(arr}, ma l'accesso alla colonna è difficile.

Se si desidera aggiungere una dipendenza di libreria, il pacchetto NumPy è ciò che si desidera veramente. È possibile creare un array di lunghezza fissa da un elenco di liste utilizzando:

import numpy 
arr = numpy.array([[1,2],[3,4]]) 

accesso Colonna è lo stesso che per le liste list-of-, ma l'accesso colonna è facile: arr[:,i] per i a {0,..,arr.shape[1]} (il numero di colonne).

In effetti gli array NumPy possono essere n-dimensionali.

array vuoti possono essere creati con

numpy.empty(shape) 

dove shape è una tupla di dimensioni in ogni dimensione; shape=(1,3,2) fornisce un array 3-d con dimensione 1 nella prima dimensione, dimensione 3 nella seconda dimensione e 2 nella terza dimensione.

Se si desidera memorizzare gli oggetti in un array NumPy, si può fare anche questo:

arr = numpy.empty((1,), dtype=numpy.object) 
arr[0] = 'abc' 

Per maggiori informazioni sul progetto NumPy, controlla la NumPy homepage.

+0

Non è necessario utilizzare la tupla. 'numpy.empty ([1])' funziona pure. – jfs

+0

Il semplice generatore di numeri "casuale": 'noise = lambda: numpy.empty ([1]) [0]' – jfs

+0

Vero, qualsiasi iterabile (elenco, tupla, ecc.) Funziona come argomento delle dimensioni. Il tuo generatore di numeri "casuale" si basa sulla memoria non inizializzata che è "casuale" e dovrebbe * mai * essere usata come fonte di casualità per tutto ciò che è maturato (ad esempio la crittografia). –

13

Per creare una matrice pitone tenore di array di dimensione arbitraria:

a = [[0]*cols for _ in [0]*rows] 

Si accede così:

a[0][1] = 5 # set cell at row 0, col 1 to 5 

Una piccola Gotcha pitone che vale la pena menzionare: Si è tentati di digitare solo

a = [[0]*cols]*rows 

ma che ti copiare il stessa colonna array per ogni riga, con conseguente comportamento indesiderato. Vale a dire:

>>> a[0][0] = 5 
>>> print a[1][0] 
5 
+4

Preferisco usare: '[[0] * colonne per _ in xrange (righe)]' – jfs

+0

@ J.F.Sebastian Ya anche io, davvero. Ho appena trovato la simmetria accattivante al momento di scrivere questo. :-) – Deestan

+0

plus1 per il gotcha. – AShelly

10

Gli array multidimensionali sono un po 'torbidi. Ci sono pochi motivi per usarli e molte ragioni per pensarci due volte e usare qualcos'altro che rifletta più correttamente quello che stai facendo. [Suggerimento. la tua domanda era sottile sul contesto ;-)]

Se stai facendo matrice matematica, quindi utilizzare numpy.

Tuttavia, alcune persone hanno lavorato con i linguaggi che li costringono a usare array multidimensionali, perché è tutto quello che hanno ottenuto. Se sei vecchio come me (ho iniziato a programmare negli anni '70), puoi ricordare i giorni in cui gli array multidimensionali erano l'unica struttura dati che avevi. Oppure, la tua esperienza potrebbe averti limitato alle lingue in cui dovevi trasformare il tuo problema in array multidimensionali.

Supponiamo di avere una collezione n. punti 3D. Ogni punto ha un valore x, y, z e tempo. Si tratta di una serie n x 4? O un array 4 * n? Non proprio.

Da ciascun punto ha 4 valori fissi, questo è più propriamente una lista di tuple.

a = [ (x, y, z, t), (x, y, z, t), ... ] 

Ancora meglio, potremmo rappresentare questo come un elenco di oggetti.

class Point(object): 
    def __init__(self, x, y, z, t): 
     self.x, self.y, self.z, self.t = x, y, z, t 

a = [ Point(x,y,x,t), Point(x,y,z,t), ... ] 
+1

+1. Vorrei menzionare 'namedtuple's – jfs

0

Un'altra opzione è quella di usare un dizionario:

>>> from collections import defaultdict 
>>> array = defaultdict(int) # replace int with the default-factory you want 
>>> array[(0,0)] 
0 
>>> array[(99,99)] 
0 

Avrete bisogno di tenere traccia delle superiori & limiti inferiori pure.

11

Date un'occhiata a numpy

Ecco un frammento di codice per voi

import numpy as npy 

d = npy.zeros((len(x)+1, len(y)+1, len(x)+len(y)+3)) 
d[0][0][0] = 0 # although this is unnecessary since zeros initialises to zero 
d[i][j][k] = npy.inf 

Non penso che sia necessario implementare un'applicazione scientifica per giustificare l'uso di Numpy. È più veloce e flessibile e puoi memorizzare praticamente tutto. Dato che penso che sia probabilmente meglio provare e giustificare lo non usando. Ci sono motivi legittimi, ma aggiunge molto e costa pochissimo, quindi merita considerazione.

P.S. La tua serie di array è giusta? Sembra una matrice di forma abbastanza singolare ...

4

Probabilmente non è rilevante per voi, ma se si sta facendo un lavoro serio matrice vedi numpy

5

Se sei OK utilizzo di matrici sparse, è possibile utilizzare un dict per memorizzare il vostro valori. dicts di Python consentono di utilizzare tuple come chiavi, in quanto tale, è possibile assegnare da e per accedere agli elementi della "matrice sparsa" (che in realtà è un dict qui) come questo:

d = {} 
d[0,2,7] = 123 # assign 123 to x=0, y=2, z=7 
v = d[0,2,7] 
+0

Un bel trucco per memorizzare una matrice multidimensionale. Tuttavia, le cose diventerebbero molto confuse quando si tenta di iterare su elementi di una colonna o di una riga o persino di essere in grado di ottenere le 'dimensioni'. –

+0

Infatti. Se dovessi usare qualcosa del genere, ovviamente lo incapsularò in una classe e introdurrei metodi per l'accesso in lettura/scrittura. Una variabile di istanza memorizzerebbe la dimensione della matrice e i metodi di lettura/scrittura restituirebbero un valore predefinito per gli elementi non assegnati (rilevando KeyError). – paprika

+0

+1: il dizionario è notevolmente più semplice. L'iterazione su dimensioni è facile, non disordinata. xRange = set ([k [0] per k in d.keys()]), yRange = set ([k [1] per k in d.keys()]) –

2

Ecco un modo veloce per creare nested elenco 3-dimensionale inizializzato con zeri:

# dim1, dim2, dim3 are the dimensions of the array 
a =[[[0 for _ in range(dim1)] for _ in range(dim2)] for _ in range(dim1) ] 
a[0][0][0] = 1 

questa è una lista di liste di liste, un po 'più flessibile di un array, si può fare:

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

sostituire un'intera riga nell'array, o ev en abusi in quel modo:

a[0] = "Ouch" 
print a[0][0] #will print "O", since strings are indexable the same way as lists 
print a[0][0][0] #will raise an error, since "O" isn't indexable 

ma se avete bisogno di prestazioni, allora sono d'accordo che numpy è la strada da percorrere.

Inoltre, attenzione:

a = [[[0] * 5]*5]*5] 

Se si tenta a[0][0][0]=7 sull'oggetto di cui sopra, si vedrà cosa c'è di sbagliato in questo.

0

Ho appena fatto un passo in una simile esigenza e codificato questo:

def nDimensionsMatrix(dims, elem_count, ptr=[]): 
    if (dims > 1): 
     for i in range(elem_count[dims-1]): 
      empty = [] 
      ptr.append(empty) 
      nDimensionsMatrix(dims-1, elem_count, empty) 
     return ptr 
    elif dims == 1: 
     ptr.extend([0 for i in range(elem_count[dims])]) 
     return ptr 

matrix = nDimensionsMatrix(3, (2,2,2)) 

non sto guardando alla velocità, solo funcionality;)

voglio creare una matrice con N dimensioni e inizializza con 0 (a elem_count numero di elementi in ogni dimensione).

Speranza la sua aiuta qualcuno

0

facile, quando si utilizza NumPy:

b = ones((2,3,4)) # creates a 2x3x4 array containing all ones. 

'quelli' possono essere sostituiti con 'zeri'