¿Cómo convertir int [] a Integer [] en Java?

167

Soy nuevo en Java y estoy muy confundido.

Tengo un gran conjunto de datos de longitud 4 int[]y quiero contar la cantidad de veces que ocurre cada combinación particular de 4 enteros. Esto es muy similar a contar frecuencias de palabras en un documento.

Quiero crear un Map<int[], double>que asigne cada int [] a un recuento continuo a medida que la lista se repite, pero Map no toma tipos primitivos.

entonces hice Map<Integer[], Double>

mis datos se almacenan como un ArrayList<int[]>modo, mi ciclo debería ser algo así como

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

No estoy seguro de qué código necesito en el comentario para que esto funcione para convertir un int[]a un Integer[]. O tal vez estoy fundamentalmente confundido acerca de la forma correcta de hacer esto.

Jonik
fuente
66
"Quiero crear un Mapa <int [], doble> ... pero el Mapa no toma tipos primitivos". Como señaló una de las publicaciones a continuación, int [] no es un tipo primitivo, por lo que ese no es el verdadero problema. El verdadero problema es que las matrices no anulan .equals () para comparar los elementos. En ese sentido, convertir a Integer [] (como dice tu título) no te ayuda. En el código anterior, frequencies.containsKey (q) aún no funcionaría como esperaba porque usa .equals () para comparar. La solución real es no usar matrices aquí.
newacct
No quiero enviar spam con otra respuesta, pero vale la pena señalar que ahora hay un ejemplo de documentación al respecto.
Mureinik

Respuestas:

189

Java 8 nativo (una línea)

Con Java 8, int[]se puede convertir Integer[]fácilmente:

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

Como otros han dicho, Integer[]generalmente no es una buena clave de mapa. Pero en lo que respecta a la conversión, ahora tenemos un código relativamente limpio y nativo.

Sheepy
fuente
3
Mientras tanto, esa es la forma correcta. Si necesita la matriz de enteros como una lista, puede escribir:List<Integer> list = IntStream.of(q).boxed().collect(Collectors.toList());
aw-think
para convertir a una Integer[], en realidad sugeriría usar la siguiente sintaxis: Integer[] boxed = IntStream.of(unboxed).boxed().toArray();De la misma manera que @NwDx
YoYo
1
@JoD. Si, eso funciona. Pero IntStream.ofllama de Arrays.streamtodos modos. Creo que todo se reduce a la preferencia personal: prefiero una función anulada, a algunos les encanta usar clases más explícitas.
Sheepy
2
¡Esa es una solución loca pero genial! ¡Gracias!
Rugal
1
@VijayChavda La nueva sintaxis, llamada referencias de métodos , se introdujo en 2014 con Java 8 como parte de lambda ( JSR 335 Parte C ). Significa the "new" method (constructor) of the Integer[] class.
Sheepy
79

Si desea convertir un int[]a un Integer[], no hay una forma automática de hacerlo en el JDK. Sin embargo, puedes hacer algo como esto:

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

Si tiene acceso a la biblioteca lang de Apache , puede usar el ArrayUtils.toObject(int[])método de esta manera:

Integer[] newArray = ArrayUtils.toObject(oldArray);
Eddie
fuente
71
Esa es una forma desagradable de hacer un bucle for.
James Becwar
9
Esto es perfectamente normal para cada ... No veo la parte desagradable.
Dahaka
18
@Dahaka, la maldad está en usar un iterador valuemientras la variable de indexación iestá allí.
lcn
1
@Icn, puedo ver por qué algunas personas no preferirían ese estilo, pero ¿qué lo hace tan indeseable como para ser desagradable?
Eddie
14
@icn, @Dahaka: lo desagradable es que, dado que ya estás usando una variable de índice incremental, no es necesario usar un for-each, también; aunque se ve bonito y simple en el código, detrás de escena que implica una sobrecarga innecesaria. Un for (int i...)bucle tradicional sería más eficiente aquí.
Daiscog
8

Presumiblemente, desea que la clave del mapa coincida con el valor de los elementos en lugar de la identidad de la matriz. En ese caso, desea algún tipo de objeto que defina equalsy hashCodecomo era de esperar. Lo más fácil es convertir a un uso List<Integer>, ya sea uno ArrayListo mejor Arrays.asList. Mejor que eso, puede introducir una clase que represente los datos (similar a, java.awt.Rectanglepero recomiendo que las variables sean privadas finales y la clase final también).

Tom Hawtin - tackline
fuente
Oh, esto es una cuestión de conversión de matriz, simplemente al revés: stackoverflow.com/questions/564392/...
Tom Hawtin - tackline
8

Usando for-loop regular sin bibliotecas externas:

Convierta int [] a 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
}

Convertir entero [] a 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
}
plata
fuente
6

Me equivoqué en una respuesta anterior. La solución adecuada es usar esta clase como clave en el mapa que envuelve el int [] real.

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

y cambia tu código así:

   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
fuente
1
Haría la clase final, y la final privada de campo. Haga una copia defensiva de la matriz en el constructor (clon). Y simplemente devuelva el valor de Arrays.equals en lugar de tener esa declaración if peculiar. toString estaría bien.
Tom Hawtin - tackline
1
Ah, y arroje un NPE desde el constructor (probablemente llamando a clone) para datos nulos, y no tenga el check in hashCode.
Tom Hawtin - tackline
Cierto .. Pero el código para igual, hashCode es generado por IDEA :-). Funciona correctamente
Mihai Toader
6
  1. Convierta int [] a 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. Convertir entero [] a 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;
    }
Duro
fuente
2
Esto es bastante inexacto debido al autoboxing. En el primer ejemplo, simplemente puedes hacerlo newArray[i] = ids[i];y en el segundo newArray[i] = WrapperArray[i]:)
Eel Lee
3

En lugar de escribir su propio código, puede usar un IntBuffer para ajustar el int [] existente sin tener que copiar los datos en una matriz Integer

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

IntBuffer implementa herramientas comparables para que pueda usar el código que ya ha escrito. Formalmente, los mapas comparan claves de manera que a.equals (b) se usa para decir que dos claves son iguales, por lo que dos IntBuffers con matriz 1,2,3, incluso si las matrices están en diferentes ubicaciones de memoria, se dice que son iguales y también lo serán trabaja para tu código de frecuencia.

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

}

Espero que ayude

Chris
fuente
2

No estoy seguro de por qué necesita un Doble en su mapa. En términos de lo que estás tratando de hacer, ¿tienes un int [] y solo quieres contar cuántas veces ocurre cada secuencia? ¿Por qué esto requeriría un Doble de todos modos?

Lo que haría es crear un contenedor para la matriz int con los métodos .equals y .hashCode adecuados para tener en cuenta el hecho de que el objeto int [] en sí mismo no considera los datos en su versión de estos métodos.

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

}

Y luego use el multiset de google guava, que tiene el propósito exacto de contar las ocurrencias, siempre que el tipo de elemento que ingrese tenga los métodos .equals y .hashCode adecuados.

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

Luego, para obtener el recuento de cualquier combinación particular:

int cnt = multiset.count(new IntArrayWrapper(new int[] { 0, 1, 2, 3 }));
Mate
fuente
IntArrayWrapperDefinitivamente, este es el enfoque correcto para usar una int[]matriz como clave hash, pero debe mencionarse que ese tipo ya existe ... Puede usarlo para envolver una matriz y no solo lo tiene hashCodee equalsincluso es comparable.
Holger
2

Actualización: aunque se compila a continuación, arroja un ArrayStoreExceptionen tiempo de ejecución. Demasiado. Dejaré que se quede para futuras referencias.


Convertir an int[], a an Integer[]:

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

Debo admitir que me sorprendió un poco que esto se compila, dado que System.arraycopyes de bajo nivel y todo, pero lo hace. Al menos en java7.

Puede convertir a la inversa con la misma facilidad.

Thomas Ahle
fuente
2
No veo mucho valor en mantener esta respuesta "como referencia" cuando no funciona. La documentación de System.arraycopy () incluso establece que no funcionará para este propósito.
Zero3
2

¡Funcionó como por arte de magia!

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
fuente
Hola Tunaki, ¿puedes explicarme el código anterior? cuando ejecuto el depurador, veo que el método get y size se llama automáticamente, es decir, ¡¡sin que se llame explícitamente !! ¡¿Cómo es eso?! ¿Puede usted explicar por favor?
forkdbloke
0

Convierta int [] a 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
fuente
-1

no necesitas int[]es un objeto y se puede usar como clave dentro de un mapa.

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

es la definición adecuada del mapa de frecuencias.

Esto estaba mal :-). La solución adecuada también se publica :-).

Mihai Toader
fuente
Muchas gracias por su respuesta. Intenté esto primero y se compiló bien, pero parece frequencies.containsKey(q)que siempre sería falso incluso si tengo putla misma matriz dos veces. ¿Hay algún problema aquí que implique la definición de igualdad de Java con int [] 's?
1
(Sugerencia, (new int [0]). Equals (new int [0]) es falso; (new ArrayList <Integer> ()). Equals (new ArrayList <String> ()) es verdadero.
Tom Hawtin - tackline
1
Mala idea, ya que la comparación de matrices se basa en la igualdad de referencia . Es por eso que Arrays.equals () existe ...
sleske
Maldición :-). Esperaba tener razón. La declaración es correcta pero la semántica es incorrecta debido a la cuestión de la igualdad de referencia.
Mihai Toader
-3

Simplemente use:

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
fuente