2010-12-01 3 views
6

Sto attraversando un periodo difficile per riprendere la testa su come inizializzare un vettore di vettori.Vettore di inizializzazione vettoriale

typedef vector < vector < vector < vector < float>>>> DataContainer;

Voglio che questo conforme alle

level_1 (2 elements/vectors) 
    level_2 (7 elements/vectors) 
     level_3 (480 elements/vectors) 
     level_4 (31 elements of float) 

Affrontare gli elementi non è il problema. Questo dovrebbe essere semplice come qualcosa di simile a

dc[0][1][2][3]; 

Il problema è che ho bisogno di riempirlo con i dati provenienti fuori ordine da un file in modo tale che gli elementi successivi devono essere collocati qualcosa come

dc[0][3][230][22]; 
dc[1][3][110][6]; //...etc 

Quindi ho bisogno di inizializzare la V of V in anticipo.

sono io psyching io fuori o si tratta di semplice come

for 0..1 
    for 0..6 
     for 0..479 
      for 0..30 
       dc[i][j][k][l] = 0.0; 

Non sembra così dovrebbe funzionare. In qualche modo i vettori di primo livello devono essere inizializzati per primi.

Qualsiasi aiuto apprezzato. Sono sicuro che questo deve essere più semplice di quello che sto immaginando.

risposta

16
  • prega non utilizzare vettori annidati se la dimensione dello storage è noto prima del tempo, cioè non vi sia un motivo specifico perché per esempio il primo indice deve essere di dimensione 6 e non cambierà mai. Basta usare un array semplice. Meglio ancora, usa boost::array. In questo modo, ottieni tutti i vantaggi di disporre di un array semplice (salva enormi quantità di spazio quando vai multidimensionale) e dei vantaggi di avere una vera istanziazione di oggetti.

  • prega non utilizzare vettori nidificate se la memorizzazione deve essere rettangolare, vale a dire si potrebbe ridimensionare una o più delle dimensioni, ma ogni "riga" deve essere la stessa lunghezza ad un certo punto. Utilizzare boost::multi_array. In questo modo, di documentare "questa memoria è rettangolare", risparmiare enormi quantità di spazio e ancora ottenere la possibilità di ridimensionare, vantaggi di avere un oggetto reale, ecc

La cosa std::vector è che (un) è pensato per essere ridimensionabile e (b) non si preoccupa del suo contenuto nel minimo, purché siano del tipo corretto. Ciò significa che se si dispone di un vector<vector<int> >, tutti i "vettori di riga" devono conservare le proprie informazioni di conservazione separata per quanto tempo sono - anche se si vuole far rispettare che sono tutti della stessa lunghezza.Significa anche che gestiscono allocazioni di memoria separate, il che danneggia le prestazioni (comportamento della cache) e spreca ancora più spazio a causa del riallineamento di std::vector. boost::multi_array è progettato con l'aspettativa che si desideri ridimensionarlo, ma non lo ridimensioneremo costantemente aggiungendo elementi (righe, per una matrice/facce bidimensionali, per una matrice tridimensionale/ecc.) Alla fine . std::vector è progettato per (potenzialmente) sprecare spazio per assicurarsi che l'operazione non sia lenta. boost::multi_array è progettato per risparmiare spazio e mantenere tutto ordinatamente organizzato in memoria.

Detto:

Sì, si ha bisogno di fare qualcosa prima che è possibile indicizzare nel vettore. std::vector non causerà magicamente l'esistenza degli indici perché si desidera memorizzare qualcosa lì. Tuttavia, questo è facile da gestire:

È possibile inizializzare il vettore con la quantità di zeri appropriata prima e quindi sostituirli, utilizzando il costruttore (size_t n, const T& value = T()). Cioè,

std::vector<int> foo(10); // makes a vector of 10 ints, each of which is 0 

perché un int "default-costruito" ha il valore 0.

Nel tuo caso, abbiamo bisogno di specificare la dimensione di ogni dimensione, con la creazione di sub-vettori che sono di dimensioni appropriate e lasciando che il costruttore le copi. Questo appare come:

typedef vector<float> d1; 
typedef vector<d1> d2; 
typedef vector<d2> d3; 
typedef vector<d3> d4; 
d4 result(2, d3(7, d2(480, d1(31)))); 

Cioè, un anonimo d1 è costruito di dimensioni 31, che viene utilizzato per inizializzare il default d2, che viene utilizzato per inizializzare il default d3, che viene utilizzato per inizializzare result.

Ci sono altri approcci, ma sono molto più goffi se si desidera iniziare un gruppo di zeri. Se avete intenzione di leggere l'intero set di dati da un file, però:

  • È possibile utilizzare .push_back() da aggiungere a un vettore. Creare un numero vuoto d1 subito prima del ciclo più interno, nel quale si è ripetutamente inserito .push_back(). Subito dopo il ciclo, hai il risultato su d2 che hai creato prima del ciclo successivo più interno e così via.

  • È possibile ridimensionare un vettore in anticipo con .resize() e quindi indicizzarlo normalmente (fino all'ammontare che è stato ridimensionato).

+0

Neat costruzione lì. Darò un boost a multi_array. Grazie per la risposta approfondita. – ValenceElectron

+2

Nel nuovo standard C++, la funzionalità di 'boost :: array' è fornita da' std :: array' nella libreria standard. –

0

Probabilmente si dovrà impostare un formato o riserva di memoria

Puoi fare una for-each o un nidificato per che chiamare

myVector.resize(x); //or size 

su ogni livello.

+0

.size() controlla la dimensione corrente del vettore. Vuoi .resize(). –

1

MODIFICA: Ammetto che questo codice non è elegante. Mi piace la risposta @Karl, che è la strada giusta da percorrere.

Questo codice è stato compilato e testato. Ha stampato 208320 zeri che è previsto (2 * 7 * 480 * 31)

#include <iostream> 
#include <vector> 

using namespace std; 

typedef vector< vector < vector < vector<float> > > > DataContainer; 

int main() 
{ 
    const int LEVEL1_SIZE = 2; 
    const int LEVEL2_SIZE = 7; 
    const int LEVEL3_SIZE = 480; 
    const int LEVEL4_SIZE = 31; 

    DataContainer dc; 

    dc.resize(LEVEL1_SIZE); 
    for (int i = 0; i < LEVEL1_SIZE; ++i) { 
     dc[i].resize(LEVEL2_SIZE); 
     for (int j = 0; j < LEVEL2_SIZE; ++j) { 
      dc[i][j].resize(LEVEL3_SIZE); 
      for (int k = 0; k < LEVEL3_SIZE; ++k) { 
       dc[i][j][k].resize(LEVEL4_SIZE); 
      } 
     } 
    } 

    for (int i = 0; i < LEVEL1_SIZE; ++i) { 
     for (int j = 0; j < LEVEL2_SIZE; ++j) { 
      for (int k = 0; k < LEVEL3_SIZE; ++k) { 
       for (int l = 0; l < LEVEL4_SIZE; ++l) { 
        dc[i][j][k][l] = 0.0; 
       } 
      } 
     } 
    } 

    for (int i = 0; i < LEVEL1_SIZE; ++i) { 
     for (int j = 0; j < LEVEL2_SIZE; ++j) { 
      for (int k = 0; k < LEVEL3_SIZE; ++k) { 
       for (int l = 0; l < LEVEL4_SIZE; ++l) { 
        cout << dc[i][j][k][l] << " "; 
       } 
      } 
     } 
    } 

    cout << endl; 
    return 0; 
} 
+0

Questo è esattamente ciò che ho realizzato circa 30 secondi dopo la pubblicazione. Dovrebbe funzionare, ma il boost multi di Karl sembra una scelta migliore. – ValenceElectron