2009-07-10 17 views
54

Wdrażam interfejs, który ma funkcjonalność podobną do tabeli, która może zawierać typy obiektów. Interfejs określa następującą funkcję:Jak przekonwertować Double [], aby podwoić []?

double[] getDoubles(int columnIndex); 

Gdzie jestem zakłopotany, że w mojej realizacji, ja przechowywania danych w tabeli 2D Object tablicy (Object[][] data). Kiedy muszę przywrócić wartości, chcę wykonać następujące czynności (zakłada się, że getDoubles() zostanie wywołana tylko na kolumnie zawierającej podwójne, więc nie będzie żadnego ClassCastExceptions):

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

Ale - Java nie robi Pozwól, aby Object[] zostało przesłane do double[]. Przesyłanie go do Double[] jest ok, ponieważ Double jest obiektem, a nie prymitywem, ale mój interfejs określa, że ​​dane zostaną zwrócone jako double[].

Mam więc dwa pytania:

  1. Czy jest jakiś sposób mogę uzyskać dane z kolumn tabeli Object[][] i zwróci tablicę prymitywów?
  2. Jeśli zmienię interfejs w celu zwrócenia Double[], czy wystąpi jakikolwiek wpływ na wydajność?
+0

Dlaczego potrzebujesz danych jako Object [] []? – notnoop

+0

W tabeli można przechowywać wszelkiego rodzaju dane: ciągi, duble, liczby całkowite, inne typy itp. – Brian

+0

W takim razie, w jaki sposób można zagwarantować, że tablica w columnIndex zawiera tylko podwójne/podwójne? – notnoop

Odpowiedz

31

Niestety trzeba będzie pętli całą listę i unbox się Double jeśli chcesz przekonwertować go do double[].

Jeśli chodzi o wydajność, jest trochę czasu związanego z prymitywami boksu i rozpakowywania w Javie. Jeśli zestaw jest wystarczająco mały, nie wystąpią żadne problemy z wydajnością.

+4

Chociaż nie jest to bezpośrednio stosowane, testy w języku C# podczas sortowania dużych (miliony elementów) tablic z typami pierwotnymi i pudełkowymi wykazały, że sortowanie pierwotne jest 3 razy szybsze. Wspominam o tym, ponieważ ilustruje to, że koszt automatycznego boksu/rozpakowania może być znaczący. – cletus

+0

Wow. To jest o wiele ważniejsze, niż bym się spodziewał. Nie rozważałbym jednak 1 miliona małego zestawu. – jjnguy

3

Jeśli chcesz zwrócić double[], musisz utworzyć new double[], wypełnić go i zwrócić.

To może być dobra decyzja dotycząca architektury. Po pierwsze, nie ma sensu rzutować na Object[] na Double[]; nie jest to tak naprawdę tablica z Double, ponieważ może tam być także Object s. Po drugie, jeśli bezpośrednio zwrócisz tablicę, kod użytkownika może ją zmodyfikować i zmienić wewnętrzną strukturę obiektu.

Najważniejszym skutkiem wydajności będzie zwrócenie tablicy double[] z powodu rozpakowania i kosztu przydziału.

7

Możesz użyć a dla każdej pętli, aby zbudować tablicę tymczasową o tym samym rozmiarze, a następnie rzutuj każdy element na podwójne, ale w tablicy.

SO:

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

Proszę mnie poprawić, jeśli jestem w błędzie tutaj.

+0

Ten jest w rzeczywistości prostszym rozwiązaniem niż inne. – Ryde

76

Jeśli nie masz nic przeciwko używaniu biblioteki innej firmy, commons-lang ma typ ArrayUtils z różnymi metodami manipulacji.

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

Istnieje również metoda komplementarna

doubles = ArrayUtils.toObject(d); 

Edycja: Aby odpowiedzieć na resztę kwestii. Będzie to trochę kłopotliwe, ale jeśli tablica jest naprawdę duża, nie powinieneś się o to martwić. Przetestuj go najpierw, aby sprawdzić, czy jest to problem przed refaktoryzacją.

Wdrożenie metody, o którą pytałeś, dałoby coś takiego.

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

Dzięki za informację, że commons-lang ma tę funkcję, będzie bardzo przydatna w przyszłości, jeśli zdecyduję się pójść z bibliotekami innych firm – Brian

+0

Wolę to od odpowiedzi przepuszczanie. O wiele lepiej jest używać API innej firmy do kodu standardowego, takiego jak ten – Richard

+5

przy użyciu bibliotek innych firm, które mogą wyglądać dobrze (w końcu jeden kod liniowy wygląda o wiele lepiej niż brzydka pętla for ...), ale implementacja nie różni się od ręcznej podwójnej konwersji. Najgorszy!Istnieje nawet potrójny operator dla każdej iteracji, która może spowodować jeszcze więcej przetwarzania komputerowego. Chodzi mi o to, że "preferowanie" rozwiązania powinno uwzględniać wydajność i użyteczność w stosunku do estetyki kodu. :) my 2c. –

0

będę sekunda ArrayUtils odbierać i dodać, że 1,5 autoboxing documentation (via) trochę wynika, że ​​nie ma wbudowanego sposób:

Nie ma dozwolony konwersji z macierzowych SC [] na tablicy typ TC [], jeśli nie jest dozwolona konwersji innego niż ciąg z konwersją do SC TC

1

nie mam nic do dodania do rzeczywistej pytanie poza jjnguy i Eric K powiedział oslow.

Ale tylko jedna uwaga: wspominasz o rzucaniu tablicy obiektów do podwójnej tablicy. Następujące funkcje NIE będą działać:

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; 

Ostatnia linia rzuci wyjątek odlewu klasowego. Mimo że każdy element tablicy jest rzeczywiście podwójnym, tablica została utworzona jako tablica obiektów, a nie tablica podwójna, więc rzutowanie jest nieważne.

32

W Javie 8, jest to jedno-liner:

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

Zauważ, że to jeszcze iteracje nad oryginalnej tablicy i tworzy nową.

+0

Tego właśnie szukałem! –

1

Można wykorzystać ArrayUtils przekonwertować

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

nie potrzebuje pętli wszystkich danych.

Powiązane problemy