Domanda

Devo archiviare una raccolta di INT e doppi (che rappresentano dati nominali e apprezzati) in C ++. Potrei ovviamente conservarli tutti in un std::vector<double> , ma questo sembra un po 'sbagliato e non ottiene i punti bonus estetici.

Potrei anche cucinare qualcosa in base al polimorfismo, ma ho anche bisogno che la collezione sia davvero efficiente: sia la memorizzazione e il recupero dei dati nella raccolta dovrebbe essere il più veloce possibile. Trovo difficile giudicare se una tale soluzione sarebbe al massimo efficiente.

Ho anche trovato Boost :: Variant, che potrebbe essere di aiuto qui.

Informazioni aggiuntive: il numero di elementi nella raccolta sarà piccolo (<100) e noto quando inizializza la raccolta.

Riassumendo: potrei ovviamente risolverlo in innumerevoli modi, ma non sono sicuro di quale sarebbe una buona soluzione quando (i) l'efficienza è davvero importante e (ii) voglio anche scrivere un codice un po 'carino. Qual è la mia scommessa migliore qui?

Modifica, ulteriori informazioni: La raccolta rappresenta una "riga" in un set di dati più ampio, i suoi elementi rappresentano i valori di alcune "colonne". Le proprietà delle righe sono note, quindi è noto che tipo di dati vengono archiviati in quale posizione. L '"efficienza" di cui sto parlando è principalmente l'efficienza del recupero del valore INT/doppio di una determinata colonna, sebbene anche un'impostazione rapida dei valori sia importante. Ho alcune funzioni che operano sui dati che devono recuperarli il più velocemente possibile. Esempio:

typedef std::vector<double> Row;

void doubleFun(Row const &row)
{
    // Function knows there's always a double at index 0
    double value = row[0];
    ...
}

void integerFun(Row const &row)
{
    // Function knows there's always an integer at index 1
    int value = row[1];
    ...
}

Dopo un po 'più di pensiero e lettura dei suggerimenti finora, sembra che solo archiviare colonne Int e doppie colonne in due vettori separati sia una soluzione solida. La collezione Row Potrebbe quindi definire due diversi membri per il recupero di dati nominali e reali che le funzioni possono utilizzare.

Sto solo conservando come un vector<double> va bene anche io immagino, ma dipende dalla velocità con cui è la conversione tra doppia e int (che è probabilmente piuttosto impressionante).

Mi dispiace per essere stato un po 'poco chiaro all'inizio, spero che sia più chiaro e ora e che io possa avere qualche più pensiero sulla questione.

È stato utile?

Soluzione

L'ordinazione è un punto importante nel tuo contenitore?

In caso contrario:

class MyContainer
{
    std::vector<double> doubles;
    std::vector<int>    ints;

    push(double value) { doubles.push_back(value); }
    push(int value)    { ints.push_back(value); }

   ....
};

La parte dell'iteratore (per sfogliare l'intero contenitore) potrebbe essere un po 'più complicata ...

Altri suggerimenti

Perché non usare direttamente un vettore di doppio? Poiché i numeri interi possono essere convertiti in doppio senza perdita di precisione ... mi sembra la soluzione più semplice ed efficiente.

Ciò che resta da impostare (e non sono riuscito a capire dalla tua domanda) come puoi fare la differenza tra valori normali e reali. Il problema rimane aperto in qualsiasi soluzione che potresti scegliere.

È possibile utilizzare un tipo di unione e usarlo nel tuo vettore. Ma in tal caso dovresti avere un modo per sapere quali elementi del vettore dovrebbero essere trattati come INT e quali dovrebbero essere trattati come doppi. Per tenere traccia di quali sono INT e quali sono doppi potresti usare un bitset o qualcosa del genere.

Non sono sicuro se il tuo obiettivo sia evitare calcoli di punti galleggianti pesanti. In tal caso, il bitset può essere più efficiente. In caso contrario, e esatto INT Precision non è importante, allora potresti anche conservare tutti come doppi.

#include <vector>
#include <bitset>

union di
{
    double d;
    int i;
};


int main(int argc, char* argv[])
{

    std::bitset<2> bitsetInts;

    std::vector<di> v;
    di e1;
    e1.d = 3.9;
    v.push_back(e1);

    di e2;
    e2.i = 3;
    bitsetInts.set(1);
    v.push_back(e2);

    return 0;
}

Vorrei andare per il boost::variant Soluzione, si adatta perfettamente alle tue esigenze.

C'è la tupla boost, che puoi usare se conosci i tipi al momento della compilazione. Ma se il numero di articoli è piccolo, in modo efficiente nel perdere 100 byte non dovrebbe essere un problema.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top