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.