2012-04-26 33 views
90

Tengo una matriz de primitivos, por ejemplo para int, int [] foo. Puede ser de tamaño pequeño o no.Convertir Java Array a Iterable

int foo[] = {1,2,3,4,5,6,7,8,9,0}; 

¿Cuál es la mejor manera de crear un Iterable<Integer> de él?

Iterable<Integer> fooBar = convert(foo); 

Notas:

Por favor, no responder usando bucles

También tenga en cuenta que

int a[] = {1,2,3}; 
List<Integer> l = Arrays.asList(a); 
(a menos que se puede dar una buena explicación de cómo el compilador de hacer algo inteligente acerca de ellos?)

Ni siquiera compilar

Type mismatch: cannot convert from List<int[]> to List<Integer> 

También verifique Why is an array not assignable to Iterable? antes de responder.

Además, si utiliza alguna biblioteca (por ejemplo, Guava), explique por qué es la mejor. (Debido a que es de Google no es una respuesta completa: P)

Por último, ya que parece que hay una tarea al respecto, evite publicar el código de tareas.

+0

posible duplicado de [Iterador para matriz] (http://stackoverflow.com/questions/3912765/iterator-for-array) – NPE

+0

Agréguelos a una Lista Vinculada y luego solo devuelva el iterador de ese Conjunto. –

Respuesta

77
Integer foo[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; 

List<Integer> list = Arrays.asList(foo); 
// or 
Iterable<Integer> iterable = Arrays.asList(foo); 

Aunque es necesario utilizar una gran variedad Integer (no una matriz int) para que esto funcione.

Por primitivas, utilice la guayaba:

Iterable<Integer> fooBar = Ints.asList(foo); 
<dependency> 
    <groupId>com.google.guava</groupId> 
    <artifactId>guava</artifactId> 
    <version>15.0</version> 
    <type>jar</type> 
</dependency> 
+7

Dos notas: 1) tiene 'int', no' Integer' 2) 'List' ya es' Iterable', por lo que la tercera línea no tiene sentido. – maksimov

+1

necesita Iterable por eso hay una tercera línea. – fmucar

+1

Entonces la segunda línea no tiene sentido entonces? ;) – maksimov

33

sólo mis 2 centavos:

final int a[] = {1,2,3}; 

java.lang.Iterable<Integer> aIterable=new Iterable<Integer>() { 

    public Iterator<Integer> iterator() { 
     return new Iterator<Integer>() { 
      private int pos=0; 

      public boolean hasNext() { 
       return a.length>pos; 
      } 

      public Integer next() { 
       return a[pos++]; 
      } 

      public void remove() { 
       throw new UnsupportedOperationException("Cannot remove an element of an array."); 
      } 
     }; 
    } 
}; 
+4

remove() no es necesario en java 8, porque es un método predeterminado que arroja UnsupportedOperationException. Solo si desea proporcionar un mejor mensaje de explicación. – Alex

+0

+1 Hago algo similar para crear un 'Iterator ' desde una 'Cadena'. Implementar su propio 'iterador' parece ser la única manera de evitar iterar innecesariamente a través de todos los valores para convertir del tipo de objeto al tipo primitivo (a través de' Ints.asList() 'de Guava, por ejemplo), solo para poder obtener un 'Iterator' de la' List' que se creó. – spaaarky21

+1

Tienes razón Alex. Se agregaron los métodos predeterminados a Java 8. En 2013 agregué esta antigua pieza de código aquí. –

19

guayaba proporciona el adaptador que desea como Int.asList(). No hay un equivalente para cada tipo primitivo en la clase asociada, por ejemplo, para Booleansboolean, etc.

int foo[] = {1,2,3,4,5,6,7,8,9,0}; 
Iterable<Integer> fooBar = Ints.asList(foo); 
for(Integer i : fooBar) { 
    System.out.println(i); 
} 

Las sugerencias anteriores para utilizar Arrays.asList no va a funcionar, incluso si se compilan porque se obtiene un lugar de Iterator<int[]>Iterator<Integer>. Lo que sucede es que en lugar de crear una lista respaldada por su matriz, creó una lista de matrices de 1 elemento, que contiene su matriz.

8

que tenían el mismo problema y lo resolvió así:

final YourType[] yourArray = ...; 
return new Iterable<YourType>() { 
    public Iterator<YourType> iterator() { 
    return Iterators.forArray(yourArray); // Iterators is a Google guava utility 
    } 
} 

El iterador en sí es un vago UnmodifiableIterator pero eso es exactamente lo que necesitaba.

3

En primer lugar, estoy de acuerdo en que Arrays.asList(T...) es claramente la mejor solución para los tipos Wrapper o matrices con tipos de datos no primitivos. Este método llama a un constructor de una simple implementación privada AbstractList estática en la clase Arrays que básicamente guarda la referencia de matriz dada como campo y simula una lista anulando los métodos necesarios.

Si puede elegir entre un tipo primitivo o un tipo Contenedor para su matriz, usaría el tipo Contenedor para tales situaciones, pero por supuesto, no siempre es útil o necesario. Habría sólo dos posibilidades que puede hacer:

1) Puede crear una clase con un método estático para cada matriz tipo de datos primitivo (boolean, byte, short, int, long, char, float, double devolver un Iterable< WrapperType > Estos métodos usarían clases anónimas de Iterator (además Iterable). que pueden contener la referencia del argumento del método compuesto (por ejemplo, un int[]) como campo para implementar los métodos.

-> Este enfoque es eficaz y le ahorra memoria (excepto la memoria de los recién creados métodos, aunque, usando Arrays.asList() tomaría la memoria de la misma manera)

2) Dado que las matrices no tienen métodos (como se leerán en el lado que se ha vinculado), tampoco pueden proporcionar una instancia Iterator. Si realmente es demasiado perezoso para escribir nuevas clases, debe usar una instancia de una clase ya existente que implemente Iterable porque no hay otra alternativa que crear instancias de Iterable o un subtipo.
La ÚNICA manera de crear un derivado de Colección existente implementando Iterable es usar un bucle (excepto que use clases anónimas como se describió anteriormente) o instanciar una clase implementadora Iterable cuyo constructor permita una matriz tipo primitiva (porque Object[] no permite matrices con elementos de tipo primitivo) pero hasta donde yo sé, la API de Java no tiene una clase como esa.

El motivo del bucle se puede explicar fácilmente:
para cada colección que necesite Los objetos y los tipos de datos primitivos no son objetos. Los objetos son mucho más grandes que los tipos primitivos, por lo que requieren datos adicionales que se deben generar para cada elemento de la matriz de tipos primitivos. Eso significa que si dos formas de tres (usando Arrays.asList(T...) o utilizando una colección existente) requieren un agregado de objetos, debe crear para cada valor primitivo de su matriz int[] el objeto envoltorio. La tercera forma usaría la matriz como está y la usaría en una clase anónima, ya que creo que es preferible debido al rápido rendimiento.

También hay una tercera estrategia que usa un Object como argumento para el método donde desea usar la matriz o Iterable y requeriría verificaciones de tipo para averiguar qué tipo tiene el argumento, sin embargo, no lo recomendaría en absoluto como generalmente debe considerar que el Objeto no siempre tiene el tipo requerido y que necesita un código separado para ciertos casos.

En conclusión, es el error del sistema tipo genérico problemático de Java que no permite utilizar tipos primitivos como tipo genérico que ahorraría una gran cantidad de código utilizando simplemente Arrays.asList(T...). Entonces necesita programar para cada matriz de tipo primitivo, necesita, tal método (que básicamente no hace diferencia para la memoria utilizada por un programa C++ que crearía para cada argumento de tipo usado un método separado.

20

Con Java 8 , se puede hacer esto.

final int[] arr = {1, 2, 3}; 
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator(); 
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator(); 
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator(); 
-1

en la corriente IntSteam java8 puede ser en caja para transmitir de números enteros.

public static Iterable<Integer> toIterable(int[] ints) { 
    return IntStream.of(ints).boxed().collect(Collectors.toList()); 
} 

creo cuestiones de rendimiento basados ​​en el tamaño de la matriz.

4

Puede utilizar IterableOf de Cactoos:

Iterable<String> names = new IterableOf<>(
    "Scott Fitzgerald", "Fyodor Dostoyevsky" 
); 

A continuación, puede convertirlo en una lista utilizando ListOf:

List<String> names = new ListOf<>(
    new IterableOf<>(
    "Scott Fitzgerald", "Fyodor Dostoyevsky" 
) 
); 

O simplemente esto:

List<String> names = new ListOf<>(
    "Scott Fitzgerald", "Fyodor Dostoyevsky" 
); 
Cuestiones relacionadas