2009-07-10 14 views
54

Sto implementando un'interfaccia con funzionalità simili a una tabella che può contenere tipi di oggetti. L'interfaccia specifica la seguente funzione:Come si converte Double [] in double []?

double[] getDoubles(int columnIndex); 

Dove stumped è che nel mio attuazione, sto memorizzare i dati della tabella in un array 2D Object (Object[][] data). Quando ho bisogno di restituire i valori, voglio fare il seguente (si presume che getDoubles() sarà chiamato solo su una colonna che contiene doppie, quindi non ci sarà alcun ClassCastExceptions):

double[] getDoubles(int columnIndex) { 
    return (double[]) data[columnIndex]; 
} 

Ma - Java doesn consentire di trasmettere Object[] a double[]. Trasmetterlo a Double[] è ok perché Double è un oggetto e non un primitivo, ma la mia interfaccia specifica che i dati verranno restituiti come double[].

Così ho due domande:

  1. C'è un modo per ottenere i dati della colonna fuori dal tavolo Object[][] e restituire la matrice di primitive?
  2. Se cambio l'interfaccia per restituire Double[], ci sarà un impatto sulle prestazioni?
+0

Perché è necessario disporre di dati come oggetto [] []? – notnoop

+0

La tabella può memorizzare qualsiasi tipo di dati: stringhe, doppi, numeri interi, altri tipi, ecc. – Brian

+0

Quindi, come si può assicurare che l'array sul columnIndex contenga solo il doppio/doppio? – notnoop

risposta

31

Purtroppo è necessario scorrere l'intera lista e unboxing del Double se si vuole convertirlo in un double[].

Per quanto riguarda le prestazioni, c'è un po 'di tempo associato con le primitive di boxing e unboxing in Java. Se il set è abbastanza piccolo, non vedrai problemi di prestazioni.

+4

Sebbene non direttamente applicabile, i test in C# sull'ordinamento di array di grandi dimensioni (un milione di elementi) con tipi primitivi vs in scatola hanno mostrato che il tipo primitivo era 3 volte più veloce. Lo dico perché illustra il costo dell'auto-boxing/unboxing può essere significativo. – cletus

+0

Wow. È molto più significativo di quanto mi sarei aspettato. Però non prenderei in considerazione 1 milione di piccoli set. – jjnguy

3

Se si desidera restituire uno double[], sarà necessario creare uno new double[], popolarlo e restituirlo.

Questa potrebbe essere una buona decisione di architettura. Innanzitutto, non ha molto senso trasmettere uno Object[] a Double[]; in realtà non è una serie di Double perché potrebbero esserci anche Object s. In secondo luogo, se si restituisce direttamente l'array, il codice utente può modificarlo e modificare la struttura interna del proprio oggetto.

L'impatto delle prestazioni principali sarebbe nel restituire un array di double[], a causa di unboxing e il costo di allocazione.

7

È possibile utilizzare a per ogni ciclo per costruire un array temporaneo della stessa dimensione, quindi convertire ogni singolo elemento in doppio e l'array.

SO:

double[] tempArray = new double[data[columnIndex].length]; 
int i = 0; 
for(Double d : (Double) data[columnIndex]) { 
    tempArray[i] = (double) d; 
    i++; 
} 

Si prega di correggermi se sono morto sbagliato qui.

+0

Questo è in realtà una soluzione più semplice rispetto agli altri – Ryde

76

Se non ti dispiace usare una libreria di terze parti, commons-lang ha il tipo ArrayUtils con vari metodi per la manipolazione.

Double[] doubles; 
... 
double[] d = ArrayUtils.toPrimitive(doubles); 

C'è anche il metodo complementare

doubles = ArrayUtils.toObject(d); 

Modifica: Per rispondere al resto della domanda. Ci sarà un po 'di overhead per fare questo, ma a meno che l'array sia davvero grande non dovresti preoccuparti di questo. Provalo prima per vedere se si tratta di un problema prima del refactoring.

Implementare il metodo che avevi effettivamente chiesto avrebbe dato qualcosa di simile.

double[] getDoubles(int columnIndex) { 
    return ArrayUtils.toPrimitive(data[columnIndex]); 
} 
+0

Grazie per l'informazione che commons-lang ha quella funzionalità, sarà molto utile in futuro se deciderò di andare con qualsiasi libreria di terze parti – Brian

+0

Preferisco questo alla risposta di looping attraverso. È molto meglio usare un'API di terze parti per codice boilerplate come questo – Richard

+5

utilizzando librerie di terze parti può sembrare buono (dopo tutto, un codice di un solo liner sembra molto meglio di un brutto ciclo per ...) ma l'implementazione non è diverso da una conversione Double-to-double manuale. Peggio!C'è persino un operatore ternario per ogni iterazione che può comportare un numero ancora maggiore di elaborazioni al computer. Il mio punto è che "preferire" una soluzione dovrebbe considerare le prestazioni e l'utilità rispetto all'estetica del codice. :) mio 2c. –

0

Vorrei secondo le ArrayUtils rispondere e aggiungere che il 1,5 autoboxing documentation (via) rivela un pò che non v'è alcun modo incorporato:

Non v'è alcuna conversione consentita dal tipo di matrice SC [] per serie digitare TC [] se non v'è consentito conversione diversa da una conversione stringa dal SC TC

1

non ho nulla da aggiungere alla reale domanda di là di quanto jjnguy e Eric K disse Oslow.

Ma solo una nota a margine: si cita il casting di un array Oggetto su un array doppio. Non funziona:

Object[] oa=new Object[3]; 
oa[0]=new Double("1.0"); 
oa[1]=new Double("2.0"); 
oa[2]=new Double("3.0"); 
Double[] da=(Double[])oa; 

L'ultima riga genererà un'eccezione di classe. Anche se ogni elemento dell'array è effettivamente un doppio, la matrice è stata creata come una matrice di oggetti, non una matrice di doppie, quindi il cast non è valido.

32

In Java 8, questo è uno-liner:

Double[] boxed = new Double[] { 1.0, 2.0, 3.0 }; 
double[] unboxed = Stream.of(boxed).mapToDouble(Double::doubleValue).toArray(); 

Si noti che questo itera ancora oltre la matrice originale e ne crea uno nuovo.

+0

Questo è quello che stavo cercando! –

1

È possibile utilizzare le ArrayUtils convertire

Double[] d; // initialise 
double[] array = ArrayUtils.toPrimitive(d); 

Non c'è bisogno di loop tutti i dati.