Wie konvertiere ich int [] in Integer [] in Java?

166

Ich bin neu in Java und sehr verwirrt.

Ich habe einen großen Datensatz mit der Länge 4 int[]und möchte zählen, wie oft jede bestimmte Kombination von 4 Ganzzahlen auftritt. Dies ist dem Zählen von Worthäufigkeiten in einem Dokument sehr ähnlich.

Ich möchte eine erstellen Map<int[], double>, die jedes int [] einer laufenden Anzahl zuordnet, während die Liste durchlaufen wird, aber Map akzeptiert keine primitiven Typen.

also habe ich gemacht Map<Integer[], Double>

Meine Daten werden als gespeichert, ArrayList<int[]>daher sollte meine Schleife so etwas wie sein

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);
    }
}

Ich bin mir nicht sicher, welchen Code ich im Kommentar benötige, damit dies funktioniert, um einen int[]in einen zu konvertieren Integer[]. Oder vielleicht bin ich grundlegend verwirrt über den richtigen Weg, dies zu tun.

Jonik
quelle
6
"Ich möchte eine Map <int [], double> erstellen ... aber Map akzeptiert keine primitiven Typen." Wie einer der folgenden Beiträge hervorhob, ist int [] kein primitiver Typ, daher ist dies nicht das eigentliche Problem. Das eigentliche Problem ist, dass Arrays .equals () nicht überschreiben, um die Elemente zu vergleichen. In diesem Sinne hilft Ihnen die Konvertierung in Integer [] (wie Ihr Titel sagt) nicht. Im obigen Code würde Frequenzen.containsKey (q) immer noch nicht wie erwartet funktionieren, da zum Vergleichen .equals () verwendet wird. Die wirkliche Lösung besteht darin, hier keine Arrays zu verwenden.
Newacct
Ich möchte nicht mit einer anderen Antwort spammen, aber es ist erwähnenswert, dass es jetzt ein Dokumentationsbeispiel dazu gibt.
Mureinik

Antworten:

189

Native Java 8 (eine Zeile)

Mit Java 8 int[]kann Integer[]leicht konvertiert werden:

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() );

Wie andere sagten, Integer[]ist normalerweise kein guter Kartenschlüssel. Was die Konvertierung betrifft, haben wir jetzt einen relativ sauberen und nativen Code.

Schafig
quelle
3
Das ist mittlerweile der richtige Weg. Wenn Sie das Integer-Array als Liste benötigen, können Sie schreiben:List<Integer> list = IntStream.of(q).boxed().collect(Collectors.toList());
aw-think
Um in eine zu konvertieren, Integer[]würde ich tatsächlich vorschlagen, folgende Syntax zu verwenden: Integer[] boxed = IntStream.of(unboxed).boxed().toArray();In ähnlicher Weise wie @NwDx
YoYo
1
@JoD. Ja das funktioniert Aber IntStream.ofruft Arrays.streamtrotzdem an. Ich denke, es kommt auf die persönlichen Vorlieben an - ich bevorzuge eine überschriebene Funktion, manche lieben es, explizitere Klassen zu verwenden.
Sheepy
2
Das ist eine verrückte, aber großartige Lösung! Danke dir!
Rugal
1
@VijayChavda Die neue Syntax namens Methodenreferenzen wurde 2014 mit Java 8 als Teil von Lambda eingeführt ( JSR 335 Teil C ). Es bedeutet the "new" method (constructor) of the Integer[] class.
Sheepy
79

Wenn Sie ein int[]in ein konvertieren möchten Integer[], gibt es im JDK keine automatisierte Möglichkeit, dies zu tun. Sie können jedoch Folgendes tun:

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);
}

Wenn Sie Zugriff auf die Apache lang- Bibliothek haben, können Sie die folgende ArrayUtils.toObject(int[])Methode verwenden:

Integer[] newArray = ArrayUtils.toObject(oldArray);
Eddie
quelle
71
Das ist eine böse Art, eine for-Schleife zu machen.
James Becwar
9
Dies ist für jeden völlig normal ... Ich sehe den bösen Teil nicht.
Dahaka
18
@Dahaka, die Gemeinheit besteht darin, einen Iterator zu verwenden, valuewährend die Indexvariable vorhanden iist.
lcn
1
@Icn, ich kann sehen, warum manche Leute diesen Stil nicht bevorzugen, aber was macht ihn so unerwünscht, dass er böse ist?
Eddie
14
@icn, @Dahaka: Das Schlimme ist, dass Sie, da Sie bereits eine inkrementierende Indexvariable verwenden, auch keine for-each verwenden müssen. Obwohl es im Code hübsch und einfach aussieht, ist dies hinter den Kulissen mit unnötigem Overhead verbunden. Eine traditionelle for (int i...)Schleife wäre hier effizienter.
Daiscog
8

Vermutlich soll der Schlüssel zur Karte mit dem Wert der Elemente anstelle der Identität des Arrays übereinstimmen. In diesem Fall möchten Sie eine Art Objekt, das definiert equalsund hashCodewie Sie es erwarten würden. Am einfachsten ist es, in eine List<Integer>, eine ArrayListoder eine bessere Verwendung umzuwandeln Arrays.asList. Besser als das können Sie eine Klasse einführen, die die Daten darstellt (ähnlich, java.awt.Rectangleaber ich empfehle, die Variablen als privates Finale und auch als Klassenfinale zu definieren).

Tom Hawtin - Tackline
quelle
Oh, hier ist eine Frage zur Array-Konvertierung, umgekehrt: stackoverflow.com/questions/564392/…
Tom Hawtin - Tackline
8

Verwenden einer regulären for-Schleife ohne externe Bibliotheken:

Konvertiere int [] in Integer []:

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
}

Konvertiere Integer [] in int []:

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
}
Silber
quelle
6

Ich habe mich in einer früheren Antwort geirrt. Die richtige Lösung besteht darin, diese Klasse als Schlüssel in der Map zu verwenden, die das eigentliche int [] umschließt.

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;
        }
    }

und ändern Sie Ihren Code wie folgt:

   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
quelle
1
Ich würde das Klassenfinale und das Feld privat abschließen. Erstellen Sie eine defensive Kopie des Arrays im Konstruktor (Klon). Und geben Sie einfach den Wert von Arrays.equals zurück, anstatt diese eigentümliche if-Anweisung zu haben. toString wäre schön.
Tom Hawtin - Tackline
1
Oh, und werfen Sie eine NPE vom Konstruktor (der wahrscheinlich den Klon aufruft) für Nulldaten und lassen Sie den Hash-Code nicht einchecken.
Tom Hawtin - Tackline
Stimmt .. Aber der Code für gleich, hashCode wird von IDEA generiert :-). Es funktioniert richtig.
Mihai Toader
6
  1. Konvertiere int [] in Integer []

    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. Konvertiere Integer [] in int []

    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;
    }
Hart
quelle
2
Dies ist aufgrund von Autoboxen ziemlich ungenau. Im ersten Beispiel können Sie einfach tun newArray[i] = ids[i];und im zweiten newArray[i] = WrapperArray[i]:)
Eel Lee
3

Anstatt Ihren eigenen Code zu schreiben, können Sie einen IntBuffer verwenden, um das vorhandene int [] zu verpacken, ohne die Daten in ein Integer-Array kopieren zu müssen

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

IntBuffer implementiert vergleichbare Implementierungen, sodass Sie den bereits geschriebenen Code verwenden können. Formale Karten vergleichen Schlüssel so, dass a.equals (b) verwendet wird, um zu sagen, dass zwei Schlüssel gleich sind. Daher werden zwei IntBuffer mit dem Array 1,2,3 - selbst wenn sich die Arrays an verschiedenen Speicherorten befinden - als gleich bezeichnet Arbeite für deinen Frequenzcode.

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);
    }

}}

hoffentlich hilft das

Chris
quelle
2

Ich bin mir nicht sicher, warum Sie ein Double in Ihrer Karte benötigen. In Bezug auf das, was Sie versuchen, haben Sie ein int [] und möchten nur zählen, wie oft jede Sequenz auftritt? Warum sollte dies überhaupt ein Double erfordern?

Ich würde einen Wrapper für das int-Array mit den richtigen .equals- und .hashCode-Methoden erstellen, um die Tatsache zu berücksichtigen, dass das int [] -Objekt selbst die Daten in seiner Version dieser Methoden nicht berücksichtigt.

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;
    }

}

Verwenden Sie dann das Multiset von Google Guava, das genau zum Zählen von Vorkommen gedacht ist, sofern der von Ihnen eingegebene Elementtyp über die richtigen .equals- und .hashCode-Methoden verfügt.

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

Um dann die Anzahl für eine bestimmte Kombination zu erhalten:

int cnt = multiset.count(new IntArrayWrapper(new int[] { 0, 1, 2, 3 }));
Matt
quelle
Dies ist IntArrayWrapperdefinitiv der richtige Ansatz für die Verwendung eines int[]Arrays als Hash-Schlüssel, aber es sollte erwähnt werden, dass ein solcher Typ bereits existiert . Sie können ihn zum Umschließen eines Arrays verwenden und haben ihn nicht nur hashCodeund equalses ist sogar vergleichbar.
Holger
2

Update: Obwohl das Folgende kompiliert wird, wird ArrayStoreExceptionzur Laufzeit ein. Schade. Ich werde es für zukünftige Referenz bleiben lassen.


Konvertieren eines int[], in ein Integer[]:

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

Ich muss zugeben, dass ich ein bisschen überrascht war, dass dies kompiliert wird System.arraycopy es sich um Lowlevel und alles handelt, aber es tut es. Zumindest in Java7.

Sie können genauso einfach in die andere Richtung konvertieren.

Thomas Ahle
quelle
2
Ich sehe nicht viel Wert darin, diese Antwort "als Referenz" zu behalten, wenn sie nicht funktioniert. In der Dokumentation zu System.arraycopy () heißt es sogar, dass dies für diesen Zweck nicht funktioniert.
Zero3
2

Das hat wie ein Zauber gewirkt!

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
quelle
Hallo Tunaki, kannst du mir bitte den obigen Code erklären? Wenn ich den Debugger durchlaufe, sehe ich, dass die Methode get and size automatisch aufgerufen wird, dh ohne dass sie explizit aufgerufen werden !! Wie das?! Kannst du bitte Erklären?
Forkdbloke
0

Konvertiere int [] in Integer []:

    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
quelle
-1

du brauchst nicht. int[]ist ein Objekt und kann als Schlüssel in einer Karte verwendet werden.

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

ist die richtige Definition der Frequenzkarte.

Das war falsch :-). Die richtige Lösung wird auch gepostet :-).

Mihai Toader
quelle
Vielen Dank für Ihre Antwort. Ich habe dies zuerst versucht und es wurde gut kompiliert, aber es scheint frequencies.containsKey(q)immer falsch zu sein, selbst wenn ich putzweimal dasselbe Array habe. Gibt es hier einen Fehler, der Java's Definition der Gleichheit mit int [] betrifft?
1
(Hinweis, (new int [0]). Equals (new int [0]) ist false; (new ArrayList <Integer> ()). Equals (new ArrayList <String> ()) ist true.
Tom Hawtin - Tackline
1
Schlechte Idee, da der Array-Vergleich auf der Referenzgleichheit basiert . Deshalb gibt es Arrays.equals () ...
sleske
Verdammt :-). Ich hatte gehofft, ich hätte recht. Die Deklaration ist korrekt, aber die Semantik ist wegen der Referenzgleichheit falsch.
Mihai Toader
-3

Verwenden Sie einfach:

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
quelle