web-dev-qa-db-fra.com

Convertir Java Tableau en Iterable

J'ai un tableau de primitives, par exemple pour int, int [] foo. Ce pourrait être un petit, ou pas.

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

Quel est le meilleur moyen de créer un Iterable<Integer> à partir de celui-ci?

Iterable<Integer> fooBar = convert(foo);

Remarques:

Merci de 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 sera même pas compiler

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

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

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

Enfin, comme il semble y avoir un devoir à ce sujet, évitez de poster du code homeworkish.

128
ntg
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 tableau Integer (et non un tableau int) 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();
108
fmucar

juste mes 2 centimes:

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.");
            }
        };
    }
};
41

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();
27
Jin Kwon

Guava fournit l'adaptateur que vous voulez en tant que Int.asList () . Il existe un équivalent pour chaque type de primitive dans la classe associée, par exemple, Booleans pour 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 pour utiliser Arrays.asList ne fonctionneront pas, même si elles sont compilées car vous obtenez un Iterator<int[]> plutôt que Iterator<Integer>. Au lieu de créer une liste sauvegardée par votre tableau, vous avez créé une liste de tableaux comportant un seul élément, contenant votre tableau.

20
BeeOnRope

J'ai eu le même problème et 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 UnmodifiableIterator mais c'est exactement ce dont j'avais besoin.

8
mindas

Tout d'abord, je ne peux que convenir que Arrays.asList(T...) est clairement la meilleure solution pour les types Wrapper ou les tableaux contenant des types de données non primitifs. Cette méthode appelle le constructeur d'une implémentation statique privée simple AbstractList dans la classe Arrays, qui enregistre 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 ni requis. Vous ne pouvez faire que deux possibilités:

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, double renvoyant un Iterable<WrapperType>. Ces méthodes utiliseraient des classes anonymes de Iterator (outre Iterable) qui sont autorisés à contenir la référence de l'argument de la méthode comprenant (par exemple un int[]) en tant que champ afin de mettre en œuvre les méthodes.

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

2) Comme les tableaux n'ont pas de méthodes (à lire du côté que vous avez lié), ils ne peuvent pas non plus fournir d'instance Iterator. Si vous êtes vraiment trop paresseux pour écrire de nouvelles classes, vous devez utiliser une instance d'une classe existante qui implémente Iterable car il n'y a pas d'autre moyen que d'instancier Iterable ou un sous-type.
Le SEUL moyen de créer un dérivé de Collection existant implémentant Iterable consiste à utiliser une boucle (sauf que vous utilisez des classes anonymes comme décrit ci-dessus) ou instancier une classe Iterable mettant en oeuvre dont le constructeur autorise une primtive type array (car Object[] n'autorise pas les tableaux avec des éléments de type primitif) mais, autant que je sache, l'API Java ne comporte pas de classe comme celle-là.

La raison de la boucle s’explique facilement:
pour chaque collection dont vous avez besoin Les objets et les types de données primtive ne sont pas des objets. Les objets sont beaucoup plus volumineux 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 manières sur trois (en utilisant Arrays.asList(T...) ou en utilisant une Collection existante) requièrent un agrégat d'objets, vous devez créer pour chaque valeur primitive de votre tableau int[] l'objet wrapper. La troisième méthode consisterait à utiliser le tableau tel quel et à l'utiliser dans une classe anonyme, car je pense que c'est préférable en raison de la rapidité des performances.

Il existe également une troisième stratégie utilisant Object comme argument de la méthode pour laquelle vous souhaitez utiliser le tableau ou Iterable et nécessitant des contrôles de type pour déterminer le type d'argument. Cependant, je ne le recommanderais pas du tout, car vous devez généralement considérer que l’objet n’a pas toujours le type requis et que vous avez besoin de code séparé pour certains cas.

En conclusion, c'est la faute du système problématique de 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 simplement Arrays.asList(T...). Vous devez donc programmer pour chaque tableau de type primitif, une méthode de ce type (qui ne fait en principe aucune différence avec la mémoire utilisée par un programme C++, qui créerait pour chaque argument de type utilisé une méthode distincte.

3
CodingVirus01

Vous pouvez utiliser IterableOf à partir de Cactoos :

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

Ensuite, vous pouvez le transformer en une 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"
);
3
yegor256

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

1
Binod Pant