Convertir Java Array en Iterable

150

J'ai un tableau de primitives, par exemple pour int, int [] foo. Cela peut être de petite taille ou non.

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

Quelle est la meilleure façon d'en créer un Iterable<Integer>?

Iterable<Integer> fooBar = convert(foo);

Remarques:

Veuillez ne pas répondre en utilisant des boucles (à moins que vous ne puissiez donner une bonne explication sur la façon dont le compilateur fait quelque chose d'intelligent à leur sujet?)

Notez également que

int a[] = {1,2,3};
List<Integer> l = Arrays.asList(a);

Ne compilera même pas

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

Vérifiez également Pourquoi un tableau n'est-il pas attribuable à Iterable? avant de répondre.

De plus, si vous utilisez une bibliothèque (par exemple, Guava), veuillez expliquer pourquoi c'est la meilleure. (Parce que son de Google n'est pas une réponse complète: P)

Enfin, comme il semble y avoir un travail à faire à ce sujet, évitez de publier du code de travail à domicile.

ntg
la source
duplication possible de l' itérateur pour le tableau
NPE
Ajoutez-les à une LinkedList puis renvoyez simplement l'itérateur de cet ensemble.

Réponses:

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

Bien que vous deviez utiliser un Integertableau (pas un inttableau) pour que cela fonctionne.

Pour les primitives, vous pouvez utiliser la goyave:

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

Pour Java8: (d'après la réponse de Jin Kwon)

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();
fmucar
la source
10
Deux notes: 1) il a int, pas Integer2) Listest déjà Iterabledonc la troisième ligne est inutile.
maksimov
1
il a besoin d'Iterable que pourquoi il y a la troisième ligne.
fmucar
5
Les 2ème et 3ème lignes sont des options je dirais :)
fmucar
1
Cela ne fait pas partie d'un travail à la maison, j'essayais simplement d'éviter de dupliquer du code pour une fonction de débogage traitant le contenu d'un tableau ou d'une liste ... En regardant autour de moi, j'ai effectivement trouvé Arrays.asList (..);, mais au moins Eclipse semble penser qu'il ne fera pas ce que je veux (par exemple, il déduit le résultat de Arrays.asList (foo) comme List <int []>, pas List <Integer> ...) J'ai trouvé cela assez intéressant pour un question ... (-Breaking comment in parts cause of limits-)
ntg
1
En général, on pouvait penser à de nombreuses façons de le faire, mais je me demandais quel est le MEILLEUR (par exemple, une boucle serait à mon avis plus lente que ... {eh bien, le problème est que je ne peux penser à rien !: )}) Consultez également stackoverflow.com/questions/1160081/ ... pour une discussion sur pourquoi, ma question n'est pas pourquoi, mais comment, et quel type de conteneur serait le meilleur (pourquoi ArrayList? En fait, je pourrais imaginer un AbstractList wrapper utilisant Generics .., dépend probablement de la taille ...)
ntg
44

juste mes 2 cents:

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.");
            }
        };
    }
};
Joerg Ruethschilling
la source
9
remove () n'est pas nécessaire dans java 8, car c'est une méthode par défaut qui lance une exception UnsupportedOperationException. Uniquement si vous souhaitez fournir un meilleur message d'explication.
Alex le
+1 Je fais quelque chose de similaire pour créer un fichier à Iterator<Character>partir d'un fichier String. Implémenter le vôtre Iteratorsemble être le seul moyen d'éviter d'itérer inutilement toutes les valeurs à convertir du type d'objet au type primitif (via Guava Ints.asList()par exemple), juste pour pouvoir obtenir un Iteratorde celui Listqui a été créé.
spaaarky21
2
Vous avez raison Alex. Des méthodes par défaut ont été ajoutées à Java 8. En 2013, j'ai ajouté cet ancien morceau de code ici.
Joerg Ruethschilling
29

Avec Java 8, vous pouvez le faire.

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();
Jin Kwon
la source
20

Guava fournit l'adaptateur souhaité en tant que Int.asList () . Il existe un équivalent pour chaque type primitif dans la classe associée, par exemple Booleanspour boolean, 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);
}

Les suggestions ci - dessus à l' utilisation Arrays.asListne fonctionnera pas, même si elles compilent parce que vous obtenez une Iterator<int[]>plutôt que Iterator<Integer>. Ce qui se passe, c'est qu'au lieu de créer une liste sauvegardée par votre tableau, vous avez créé une liste à 1 élément de tableaux, contenant votre tableau.

BeeOnRope
la source
juste une note: le lien ne fonctionne plus. Lien Github: github.com/google/guava/blob/master/guava/src/com/google/common/…
Orangle le
Merci @Passi, corrigé (je n'arrive plus à trouver un moyen supporté par Google pour créer un lien vers javadoc, j'ai donc lié à la source que vous avez fournie).
BeeOnRope
8

J'ai eu le même problème et je l'ai résolu comme ceci:

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

L'itérateur lui-même est un paresseux UnmodifiableIteratormais c'est exactement ce dont j'avais besoin.

mindas
la source
7

Dans Java 8 ou version ultérieure, Iterableune interface fonctionnelle est renvoyée Iterator. Vous pouvez donc le faire.

int[] array = {1, 2, 3};
Iterable<Integer> iterable = () -> Arrays.stream(array).iterator();
for (int i : iterable)
    System.out.println(i);

->

1
2
3
saka1029
la source
3

Tout d'abord, je ne peux que convenir que Arrays.asList(T...)c'est clairement la meilleure solution pour les types Wrapper ou les tableaux avec des types de données non primitifs. Cette méthode appelle un constructeur d'une AbstractListimplémentation statique privée simple dans la Arraysclasse qui enregistre essentiellement la référence de tableau donnée en tant que champ et simule une liste en remplaçant les méthodes nécessaires.

Si vous pouvez choisir entre un type primtive ou un type Wrapper pour votre tableau, j'utiliserais le type Wrapper pour de telles situations, mais bien sûr, ce n'est pas toujours utile ou obligatoire. Il n'y aurait que deux possibilités que vous pouvez faire:

1) Vous pouvez créer une classe avec une méthode statique pour chaque tableau de type de données primitif ( boolean, byte, short, int, long, char, float, doublerenvoyant un Iterable<WrapperType >. Ces méthodes utiliseraient des classes anonymes de Iterator(en plusIterable) qui sont autorisés à contenir la référence de l'argument de la méthode comprenant (par exemple un int[]) comme champ afin d'implémenter les méthodes.

-> Cette approche est performante et vous permet d'économiser de la mémoire (sauf pour la mémoire des méthodes nouvellement créées, même si l'utilisation Arrays.asList()prendrait de la mémoire de la même manière)

2) Puisque les tableaux n'ont pas de méthodes (comme à lire sur le côté vous avez lié), ils ne peuvent pas non plus fournir d' Iteratorinstance. Si vous êtes vraiment trop paresseux pour écrire de nouvelles classes, vous devez utiliser une instance d'une classe déjà existante qui implémente Iterablecar il n'y a pas d'autre moyen que l'instanciation Iterableou un sous-type.
La SEULE façon de créer une implémentation de dérivé de collection existanteIterableconsiste à utiliser une boucle (sauf que vous utilisez des classes anonymes comme décrit ci-dessus) ou que vous instanciez une Iterableclasse d'implémentation dont le constructeur autorise un tableau de type primitif (car Object[]n'autorise pas les tableaux avec des éléments de type primitif) mais pour autant que je sache, l'API Java ne présente pas une classe comme celle-là.

La raison de la boucle peut être expliquée facilement:
pour chaque collection, vous avez besoin d'objets et les types de données primitifs ne sont pas des objets. Les objets sont beaucoup plus gros que les types primitifs de sorte qu'ils nécessitent des données supplémentaires qui doivent être générées pour chaque élément du tableau de types primitifs. Cela signifie que si deux méthodes sur trois (utiliser Arrays.asList(T...)ou utiliser une collection existante) nécessitent un agrégat d'objets, vous devez créer pour chaque valeur primitive de votreint[]tableau l'objet wrapper. La troisième façon utiliserait le tableau tel quel et l'utiliserait dans une classe anonyme car je pense que c'est préférable en raison des performances rapides.

Il existe également une troisième stratégie utilisant un Objectargument en tant qu'argument pour la méthode où vous souhaitez utiliser le tableau ou Iterableet il faudrait des vérifications de type pour déterminer le type de l'argument, mais je ne le recommanderais pas du tout, car vous devez généralement le faire. considérez que l'objet n'a pas toujours le type requis et que vous avez besoin d'un code séparé dans certains cas.

En conclusion, c'est la faute du système problématique Generic Type de Java qui ne permet pas d'utiliser des types primitifs comme type générique ce qui permettrait d'économiser beaucoup de code en utilisant simplementArrays.asList(T...). Vous devez donc programmer pour chaque tableau de type primitif, vous avez besoin d'une telle méthode (qui ne fait fondamentalement aucune différence pour la mémoire utilisée par un programme C ++ qui créerait pour chaque argument de type utilisé une méthode distincte.

CodageVirus01
la source
3

Vous pouvez utiliser à IterableOfpartir de Cactoos :

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

Ensuite, vous pouvez le transformer en liste en utilisant ListOf:

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

Ou simplement ceci:

List<String> names = new ListOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);
yegor256
la source
1

Bien qu'une réponse similaire ait déjà été publiée, je pense que la raison d'utiliser le nouveau PrimitiveIterator.OfInt n'était pas claire. Une bonne solution consiste à utiliser Java 8 PrimitiveIterator car il est spécialisé pour les types int primitifs (et évite la pénalité supplémentaire de boxing / unboxing):

    int[] arr = {1,2,3};
    // If you use Iterator<Integer> here as type then you can't get the actual benefit of being able to use nextInt() later
    PrimitiveIterator.OfInt iterator = Arrays.stream(arr).iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.nextInt());
        // Use nextInt() instead of next() here to avoid extra boxing penalty
    }

Réf: https://doc.bccnsoft.com/docs/jdk8u12-docs/api/java/util/PrimitiveIterator.OfInt.html

Pantalon Binod
la source
-2

Dans java8, le flux IntSteam peut être encadré en flux d'entiers.

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

Je pense que les performances sont importantes en fonction de la taille du tableau.

Soumyakanta Mohapatra
la source