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ć.

Jonik
źródło
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.

Owca
źródło
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);
Eddie
źródło
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).

Tom Hawtin - haczyk
źródło
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
}
srebro
źródło
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);
    }
Mihai Toader
źródło
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;
    }
    
Szorstki
źródło
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

Chris
źródło
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 }));
Matt
źródło
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ę.

Thomas Ahle
źródło
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);
Itamar Borges
źródło
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]);
zemiak
źródło
-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 :-).

Mihai Toader
źródło
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;
}
Lurzapps
źródło