Jak przekonwertować int [] na Integer [] w Javie?


167

Jestem nowy w Javie i bardzo zdezorientowany.

Mam duży zbiór danych o długości 4 int[]i chcę policzyć, ile razy występuje każda określona kombinacja 4 liczb całkowitych. Jest to bardzo podobne do liczenia częstości występowania słów w dokumencie.

Chcę utworzyć Map<int[], double>odwzorowanie każdego int [] na bieżącą liczbę, gdy lista jest iterowana, ale Map nie przyjmuje typów pierwotnych.

więc zrobiłem Map<Integer[], Double>

moje dane są przechowywane jako, ArrayList<int[]>więc moja pętla powinna wyglądać jak

ArrayList<int[]> data = ... // load a dataset`

Map<Integer[], Double> frequencies = new HashMap<Integer[], Double>();

for(int[] q : data) {

    // **DO SOMETHING TO convert q from int[] to Integer[] so I can put it in the map

    if(frequencies.containsKey(q)) {
    frequencies.put(q, tfs.get(q) + p);
    } else {
        frequencies.put(q, p);
    }
}

Nie jestem pewien, jakiego kodu potrzebuję w komentarzu, aby przekonwertować plik int[]an Integer[]. A może zasadniczo nie mam pojęcia, jak to zrobić.


6
„Chcę utworzyć Mapę <int [], double> ... ale Map nie przyjmuje typów pierwotnych”. Jak wskazał jeden z poniższych postów, int [] nie jest typem prymitywnym, więc nie stanowi to prawdziwego problemu. Prawdziwym problemem jest to, że tablice nie zastępują .equals (), aby porównać elementy. W tym sensie konwersja na Integer [] (jak mówi twój tytuł) ci nie pomaga. W powyższym kodzie Frequencies.containsKey (q) nadal nie będzie działał zgodnie z oczekiwaniami, ponieważ do porównania używa .equals (). Prawdziwym rozwiązaniem jest nie używanie tutaj tablic.
newacct

Nie chcę spamować inną odpowiedzią, ale warto zauważyć, że jest teraz przykład dokumentacji na ten temat.
Mureinik

Odpowiedzi:


189

Natywna Java 8 (jeden wiersz)

Dzięki Java 8 int[]można łatwo przekonwertować na Integer[]:

int[] data = {1,2,3,4,5,6,7,8,9,10};

// To boxed array
Integer[] what = Arrays.stream( data ).boxed().toArray( Integer[]::new );
Integer[] ever = IntStream.of( data ).boxed().toArray( Integer[]::new );

// To boxed list
List<Integer> you  = Arrays.stream( data ).boxed().collect( Collectors.toList() );
List<Integer> like = IntStream.of( data ).boxed().collect( Collectors.toList() );

Jak powiedzieli inni, Integer[]zwykle nie jest to dobry klucz do mapy. Ale jeśli chodzi o konwersję, mamy teraz stosunkowo czysty i natywny kod.


3
To tymczasem właściwy sposób. Jeśli potrzebujesz tablicy Integer-Array jako listy, możesz napisać:List<Integer> list = IntStream.of(q).boxed().collect(Collectors.toList());
aw-think

aby przekonwertować na format, Integer[]sugerowałbym użycie następującej składni: Integer[] boxed = IntStream.of(unboxed).boxed().toArray();W podobny sposób jak @NwDx
YoYo

1
@JoD. Tak, to działa. Ale i tak IntStream.ofdzwoni Arrays.stream. Myślę, że sprowadza się to do osobistych preferencji - wolę jedną nadpisaną funkcję, niektórzy uwielbiają używać bardziej wyraźnych klas.
Sheepy

2
To szalone, ale świetne rozwiązanie! Dziękuję Ci!
Rugal

1
@VijayChavda Nowa składnia, zwana referencjami do metod , została wprowadzona w 2014 roku wraz z Javą 8 jako częścią lambdy ( JSR 335, część C ). To znaczy the "new" method (constructor) of the Integer[] class.
Sheepy

79

Jeśli chcesz przekonwertować an int[]na an Integer[], nie ma zautomatyzowanego sposobu, aby to zrobić w JDK. Możesz jednak zrobić coś takiego:

int[] oldArray;

... // Here you would assign and fill oldArray

Integer[] newArray = new Integer[oldArray.length];
int i = 0;
for (int value : oldArray) {
    newArray[i++] = Integer.valueOf(value);
}

Jeśli masz dostęp do biblioteki języka Apache , możesz użyć następującej ArrayUtils.toObject(int[])metody:

Integer[] newArray = ArrayUtils.toObject(oldArray);

71
to paskudny sposób na wykonanie pętli for.
James Becwar

9
To jest zupełnie normalne dla każdego ... Nie widzę tej paskudnej części.
Dahaka

18
@Dahaka, nieprzyjemność polega na używaniu iteratora, valuegdy ijest tam zmienna indeksująca .
lcn

1
@Icn, rozumiem, dlaczego niektórzy ludzie nie woleliby tego stylu, ale co sprawia, że ​​jest on tak niepożądany, że jest nieprzyjemny?
Eddie

14
@icn, @Dahaka: Nieprzyjemność polega na tym, że skoro już używasz rosnącej zmiennej indeksu, nie ma też potrzeby używania for-each; chociaż wygląda to ładnie i prosto w kodzie, za kulisami, które wiąże się z niepotrzebnym narzutem. W for (int i...)tym przypadku bardziej wydajna byłaby tradycyjna pętla.
daiscog

8

Prawdopodobnie chcesz, aby klucz do mapy pasował do wartości elementów, a nie tożsamości tablicy. W takim przypadku potrzebujesz jakiegoś obiektu, który definiuje equalsi hashCodetak jak byś oczekiwał. Najłatwiej jest przekonwertować na a List<Integer>, albo ArrayListlepiej użyć Arrays.asList. Lepiej niż to, że możesz wprowadzić klasę, która reprezentuje dane (podobnie do, java.awt.Rectangleale zalecam, aby zmienne były prywatne jako ostateczne, a klasa także jako ostateczna).


Och, oto pytanie dotyczące konwersji tablic, na odwrót: stackoverflow.com/questions/564392/ ...
Tom Hawtin - tackline

8

Używanie zwykłej pętli for bez zewnętrznych bibliotek:

Konwertuj int [] na liczbę całkowitą []:

int[] primitiveArray = {1, 2, 3, 4, 5};
Integer[] objectArray = new Integer[primitiveArray.length];

for(int ctr = 0; ctr < primitiveArray.length; ctr++) {
    objectArray[ctr] = Integer.valueOf(primitiveArray[ctr]); // returns Integer value
}

Konwertuj liczbę całkowitą [] na liczbę całkowitą []:

Integer[] objectArray = {1, 2, 3, 4, 5};
int[] primitiveArray = new int[objectArray.length];

for(int ctr = 0; ctr < objectArray.length; ctr++) {
    primitiveArray[ctr] = objectArray[ctr].intValue(); // returns int value
}

6

Myliłem się w poprzedniej odpowiedzi. Właściwym rozwiązaniem jest użycie tej klasy jako klucza w mapie opakowującej rzeczywisty int [].

public class IntArrayWrapper {
        int[] data;

        public IntArrayWrapper(int[] data) {
            this.data = data;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            IntArrayWrapper that = (IntArrayWrapper) o;

            if (!Arrays.equals(data, that.data)) return false;

            return true;
        }

        @Override
        public int hashCode() {
            return data != null ? Arrays.hashCode(data) : 0;
        }
    }

i zmień swój kod w ten sposób:

   Map<IntArrayWrapper, Double > freqs = new HashMap<IntArrayWrapper, Double>();

    for (int[] data : datas) {
        IntArrayWrapper wrapper = new IntArrayWrapper(data);

        if ( freqs.containsKey(wrapper)) {
            freqs.put(wrapper, freqs.get(wrapper) + p);
        }

        freqs.put(wrapper, p);
    }

1
Doszłam do finału klasy i finału prywatnego w terenie. Utwórz kopię obronną tablicy w konstruktorze (klon). I po prostu zwróć wartość z Arrays.equals, zamiast używać tej osobliwej instrukcji if. toString byłoby fajne.
Tom Hawtin - tackline

1
Aha i wyrzuć NPE z konstruktora (prawdopodobnie wywołując clone) dla danych null i nie miej sprawdzania w hashCode.
Tom Hawtin - tackline

Prawda .. Ale kod równa się, hashCode jest generowany przez IDEA :-). Działa poprawnie.
Mihai Toader

6
  1. Konwertuj int [] na liczbę całkowitą []

    public static Integer[] toConvertInteger(int[] ids) {
    
      Integer[] newArray = new Integer[ids.length];
         for (int i = 0; i < ids.length; i++) {
           newArray[i] = Integer.valueOf(ids[i]);
         }
       return newArray;
    }
    
  2. Konwertuj liczbę całkowitą [] na liczbę całkowitą []

    public static int[] toint(Integer[] WrapperArray) {
    
       int[] newArray = new int[WrapperArray.length];
          for (int i = 0; i < WrapperArray.length; i++) {
             newArray[i] = WrapperArray[i].intValue();
          }
       return newArray;
    }
    

2
Jest to raczej niedokładne ze względu na autoboxing. W pierwszym przykładzie możesz po prostu zrobić, newArray[i] = ids[i];aw drugim newArray[i] = WrapperArray[i]:)
Eel Lee

3

Zamiast pisać własny kod możesz użyć IntBuffer do zawijania istniejącego int [] bez konieczności kopiowania danych do tablicy Integer

int[] a = {1,2,3,4};
IntBuffer b = IntBuffer.wrap(a);

IntBuffer implementuje porównywalne, więc możesz użyć kodu, który już napisałeś. Formalnie mapy porównują klucze w taki sposób, że a.equals (b) jest używane do stwierdzenia, że ​​dwa klucze są równe, więc dwa IntBuffers z tablicą 1, 2, 3 - nawet jeśli tablice znajdują się w różnych lokalizacjach pamięci - mówi się, że są równe i tak będzie pracować dla twojego kodu częstotliwości.

ArrayList<int[]> data = ... // load a dataset`

Map<IntBuffer, Double> frequencies = new HashMap<IntBuffer, Double>();

for(int[] a : data) {

    IntBuffer q = IntBuffer.wrap(a);

    if(frequencies.containsKey(q)) {
        frequencies.put(q, tfs.get(q) + p);
    } else {
        frequencies.put(q, p);
    }

}

Mam nadzieję, że to pomoże


2

Nie wiem, dlaczego potrzebujesz Double na swojej mapie. Jeśli chodzi o to, co próbujesz zrobić, masz int [] i chcesz po prostu policzyć, ile razy występuje każda sekwencja? Dlaczego to i tak wymagało Double?

To, co bym zrobił, to utworzenie opakowania dla tablicy int z odpowiednimi metodami .equals i .hashCode, aby uwzględnić fakt, że sam obiekt int [] nie bierze pod uwagę danych w swojej wersji tych metod.

public class IntArrayWrapper {
    private int values[];

    public IntArrayWrapper(int[] values) {
        super();
        this.values = values;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(values);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        IntArrayWrapper other = (IntArrayWrapper) obj;
        if (!Arrays.equals(values, other.values))
            return false;
        return true;
    }

}

Następnie użyj multisetu google guava, który jest przeznaczony dokładnie do zliczania wystąpień, o ile typ elementu, który w nim wstawisz, ma odpowiednie metody .equals i .hashCode.

List<int[]> list = ...;
HashMultiset<IntArrayWrapper> multiset = HashMultiset.create();
for (int values[] : list) {
    multiset.add(new IntArrayWrapper(values));
}

Następnie, aby uzyskać liczbę dla określonej kombinacji:

int cnt = multiset.count(new IntArrayWrapper(new int[] { 0, 1, 2, 3 }));

To IntArrayWrapperzdecydowanie właściwe podejście do używania int[]tablicy jako klucza mieszającego, ale należy wspomnieć, że taki typ już istnieje … Możesz go użyć do zawijania tablicy i nie tylko ją ma, hashCodea equalsnawet jest porównywalny.
Holger,

2

Aktualizacja: Chociaż poniżej kompiluje się, rzuca ArrayStoreExceptionw czasie wykonywania. Szkoda. Zostawię to na przyszłość.


Konwersja an int[], do an Integer[]:

int[] old;
...
Integer[] arr = new Integer[old.length];
System.arraycopy(old, 0, arr, 0, old.length);

Muszę przyznać, że byłem trochę zaskoczony, że to się kompiluje, biorąc System.arraycopypod uwagę niski poziom i wszystko, ale tak się dzieje. Przynajmniej w java7.

Możesz równie łatwo dokonać konwersji w drugą stronę.


2
Nie widzę żadnej wartości w utrzymywaniu tej odpowiedzi „w celach informacyjnych”, gdy nie działa. Dokumentacja dla System.arraycopy () stwierdza nawet, że nie będzie działać w tym celu.
Zero3

2

To zadziałało jak urok!

int[] mInt = new int[10];
Integer[] mInteger = new Integer[mInt.length];

List<Integer> wrapper = new AbstractList<Integer>() {
    @Override
    public int size() {
        return mInt.length;
    }

    @Override
    public Integer get(int i) {
        return mInt[i];
    }
};

wrapper.toArray(mInteger);

Cześć Tunaki, czy możesz mi wyjaśnić powyższy kod? kiedy uruchamiam debugger, widzę, że metoda get i size jest wywoływana automatycznie, tj. bez ich jawnego wywoływania !! jak to?! czy możesz wyjaśnić?
forkdbloke

0

Konwertuj int [] na liczbę całkowitą []:

    import java.util.Arrays;
    ...

    int[] aint = {1,2,3,4,5,6,7,8,9,10};
    Integer[] aInt = new Integer[aint.length];

    Arrays.setAll(aInt, i -> aint[i]);

-1

nie potrzebujesz. int[]jest obiektem i może być używany jako klucz wewnątrz mapy.

Map<int[], Double> frequencies = new HashMap<int[], Double>();

jest poprawnym określeniem mapy częstotliwości.

To było złe :-). Odpowiednie rozwiązanie też jest zamieszczone :-).


Wielkie dzięki za odpowiedź. Spróbowałem najpierw tego i skompilowało się dobrze, ale wydaje się, frequencies.containsKey(q)że zawsze będzie fałszywe, nawet jeśli mam putdwa razy tę samą tablicę - czy jest tu jakiś błąd dotyczący definicji równości w Javie z int []?

1
(Hint, (new int [0]). Equals (new int [0]) is false; (new ArrayList <Integer> ()). Equals (new ArrayList <String> ()) is true.
Tom Hawtin - tackline

1
Zły pomysł, ponieważ porównanie tablic opiera się na równości odwołań . Dlatego Arrays.equals () istnieje ...
sleske

Cholera :-). Miałem nadzieję, że mam rację. Deklaracja jest poprawna, ale semantyka jest błędna z powodu równości odniesień.
Mihai Toader

-3

Po prostu użyj:

public static int[] intArrayToIntegerArray(int[] a) {
    Integer[] b = new Integer[a.length];
    for(int i = 0; i < array.length; i++){
        b[i] = a[i];
    }
    return g;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.