Come convertire int [] in intero [] in Java?


167

Sono nuovo di Java e molto confuso.

Ho un set di dati di grandi dimensioni di lunghezza 4 int[]e voglio contare il numero di volte in cui si verifica ogni particolare combinazione di 4 numeri interi. Questo è molto simile al conteggio delle frequenze delle parole in un documento.

Voglio creare un Map<int[], double>che mappi ogni int [] su un conteggio progressivo mentre l'elenco è ripetuto, ma Map non accetta tipi primitivi.

così ho fatto Map<Integer[], Double>

i miei dati sono archiviati come ArrayList<int[]> quindi il mio ciclo dovrebbe essere qualcosa di simile

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

Non sono sicuro di quale codice ho bisogno nel commento per far funzionare questo per convertire un int[]in un Integer[]. O forse sono fondamentalmente confuso sul modo giusto di farlo.


6
"Voglio creare una mappa <int [], double> ... ma Map non accetta tipi primitivi." Come ha sottolineato uno dei post di seguito, int [] non è un tipo primitivo, quindi non è questo il vero problema. Il vero problema è che le matrici non sovrascrivono .equals () per confrontare gli elementi. In tal senso, la conversione in Integer [] (come dice il titolo) non ti aiuta. Nel codice sopra, frequencies.containsKey (q) continuerebbe a non funzionare come previsto perché utilizza .equals () per il confronto. La vera soluzione è di non utilizzare gli array qui.
newacct

Non voglio fare spam con un'altra risposta, ma vale la pena notare che ora c'è un esempio di documentazione su questo.
Mureinik,

Risposte:


189

Java nativo 8 (una riga)

Con Java 8, int[]può essere convertito Integer[]facilmente:

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

Come altri hanno affermato, di Integer[]solito non è una buona chiave della mappa. Ma per quanto riguarda la conversione, ora abbiamo un codice nativo relativamente pulito.


3
Nel frattempo è nel modo giusto. Se hai bisogno di Integer-Array come elenco puoi scrivere:List<Integer> list = IntStream.of(q).boxed().collect(Collectors.toList());
aw-think,

per convertire in un Integer[]suggerirei in realtà di utilizzare la sintassi seguente: Integer[] boxed = IntStream.of(unboxed).boxed().toArray();In modo simile a @NwDx
YoYo

1
@JoD. Sì, funziona. Ma IntStream.ofchiama Arrays.streamcomunque. Penso che dipenda dalle preferenze personali: preferisco una funzione ignorata, alcuni amano usare una classe più esplicita.
Sheepy,

2
Questa è una soluzione folle ma eccezionale! Grazie!
Rugal,

1
@VijayChavda La nuova sintassi, denominata riferimenti ai metodi , è stata introdotta nel 2014 con Java 8 come parte di lambda ( JSR 335 Parte C ). Significa the "new" method (constructor) of the Integer[] class.
Sheepy,

79

Se si desidera convertire un int[]in un Integer[], non esiste un modo automatico per farlo in JDK. Tuttavia, puoi fare qualcosa del genere:

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

Se hai accesso alla libreria lang di Apache , puoi utilizzare il ArrayUtils.toObject(int[])metodo in questo modo:

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

71
questo è un brutto modo di fare un ciclo for.
James Becwar,

9
Questo è perfettamente normale per ciascuno ... Non vedo la parte cattiva.
Dahaka,

18
@Dahaka, la cattiveria sta nell'usare un iteratore valuementre iè presente la variabile di indicizzazione .
lcn,

1
@Icn, posso capire perché alcune persone non preferiscono quello stile, ma cosa lo rende così indesiderabile da essere cattivo?
Eddie,

14
@icn, @Dahaka: la cattiveria è che dal momento che stai già utilizzando una variabile di indice incrementale, non è necessario utilizzare anche un per-ciascuno; anche se sembra carino e semplice nel codice, dietro le quinte che comporta spese generali non necessarie. Un for (int i...)circuito tradizionale sarebbe più efficiente qui.
daiscog,

8

Presumibilmente si desidera che la chiave della mappa corrisponda al valore degli elementi anziché all'identità dell'array. In tal caso, desideri un tipo di oggetto che definisca equalse hashCodecome ti aspetteresti. Il più semplice è convertire in un List<Integer>, o uno ArrayListo un uso migliore Arrays.asList. Meglio di così, puoi introdurre una classe che rappresenta i dati (simile java.awt.Rectanglema ti consiglio di rendere le variabili private final e anche la classe final).


Oh, ecco una domanda di conversione di array, proprio il contrario: stackoverflow.com/questions/564392/…
Tom Hawtin - tackline

8

Utilizzo del regolare for-loop senza librerie esterne:

Converti int [] in intero []:

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
}

Converti intero [] 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
}

6

Ho sbagliato in una risposta precedente. La soluzione corretta è quella di utilizzare questa classe come chiave nella mappa che racchiude l'attuale 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;
        }
    }

e cambia il tuo codice in questo modo:

   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
Renderei la finale di classe e la finale privata di campo. Crea una copia difensiva dell'array nel costruttore (clone). E restituisci semplicemente il valore da Arrays.equals piuttosto che avere quell'istruzione if peculiare. toString sarebbe carino.
Tom Hawtin - tackline

1
Oh, e lancia un NPE dal costruttore (probabilmente chiamando clone) per dati null, e non avere il check in hashCode.
Tom Hawtin - tackline

Vero .. Ma il codice per uguale, hashCode è generato da IDEA :-). Funziona correttamente
Mihai Toader,

6
  1. Converti 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. Converti intero [] 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;
    }

2
Questo è piuttosto impreciso a causa dell'autoboxing. Nel primo esempio puoi semplicemente fare newArray[i] = ids[i];e nel secondo newArray[i] = WrapperArray[i]:)
Eel Lee

3

Anziché scrivere il proprio codice, è possibile utilizzare un IntBuffer per racchiudere l'int esistente [] senza dover copiare i dati in un array integer

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

IntBuffer implementa comparabili in modo da poter usare il codice che hai già scritto. Formalmente le mappe confrontano le chiavi in ​​modo tale che a.equals (b) sia usato per dire che due chiavi sono uguali, quindi due IntBuffer con array 1,2,3 - anche se le matrici si trovano in posizioni di memoria diverse - si dice che siano uguali e così sarà lavora per il tuo codice di frequenza.

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

}

spero che aiuti


2

Non sono sicuro del motivo per cui hai bisogno di un doppio nella tua mappa. In termini di ciò che stai cercando di fare, hai un int [] e vuoi solo contare quante volte si verifica ogni sequenza? Perché questo avrebbe richiesto comunque un doppio?

Quello che vorrei fare è creare un wrapper per l'array int con i metodi .equals e .hashCode appropriati per tenere conto del fatto che l'oggetto int [] stesso non considera i dati nella sua versione di questi metodi.

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

}

E poi usa il multiset di google guava, che ha lo scopo di contare le occorrenze, purché il tipo di elemento inserito abbia i metodi .equals e .hashCode corretti.

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

Quindi, per ottenere il conteggio per qualsiasi combinazione particolare:

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

Questo IntArrayWrapperè sicuramente l'approccio giusto per usare un int[]array come chiave hash, ma va detto che un tale tipo esiste già ... Puoi usarlo per avvolgere un array e non solo ce l'ha, hashCodeed equalsè anche comparabile.
Holger,

2

Aggiornamento: sebbene il seguente compila, genera un ArrayStoreExceptionruntime. Peccato. Lascerò che rimanga per riferimento futuro.


Conversione di un int[], in un Integer[]:

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

Devo ammettere che sono rimasto un po 'sorpreso dal fatto che questo System.arraycopycompili , dato che è di basso livello e tutto il resto, ma lo fa. Almeno in Java7.

Puoi convertire dall'altra parte altrettanto facilmente.


2
Non vedo molto valore nel mantenere questa risposta "come riferimento" quando non funziona. La documentazione per System.arraycopy () afferma anche che non funzionerà per questo scopo.
Zero3

2

Questo ha funzionato come un fascino!

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

Ciao Tunaki, puoi spiegarmi il codice sopra? quando corro attraverso il debugger, vedo che il metodo get e size viene chiamato automaticamente, cioè senza che vengano chiamati esplicitamente !! come mai?! puoi spiegare per favore?
forkdbloke,

0

Converti int [] in intero []:

    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

non hai bisogno. int[]è un oggetto e può essere utilizzato come chiave all'interno di una mappa.

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

è la definizione corretta della mappa delle frequenze.

Questo era sbagliato :-). Viene pubblicata anche la soluzione corretta :-).


Mille grazie per la tua risposta. Ho provato prima e compilato bene, ma sembra che frequencies.containsKey(q)sarebbe sempre falso anche se avessi putlo stesso array due volte - c'è qualche problema qui che coinvolge la definizione di uguaglianza di Java con int [] 's?

1
(Suggerimento, (new int [0]). Equals (new int [0]) è falso; (new ArrayList <Integer> ()). Equals (new ArrayList <String> ()) è vero.
Tom Hawtin - tackline

1
Cattiva idea, poiché il confronto di array si basa sull'uguaglianza di riferimento . Ecco perché Arrays.equals () esiste ...
sleske,

Dannazione :-). Speravo di aver ragione. La dichiarazione è corretta ma la semantica è sbagliata a causa dell'uguaglianza di riferimento.
Mihai Toader,

-3

Usa semplicemente:

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.