87 votes

Java: ajout d'éléments à une collection au cours d'une itération

Est-il possible d'ajouter des éléments à une collection lors de l'itération sur elle?

Plus précisément, je voudrais effectuer une itération sur une collection, et si un élément satisfait une certaine condition, je veux ajouter quelques autres éléments de la collection, et assurez-vous que ces éléments sont itéré ainsi. (Je me rends compte que cela pourrait conduire à une unterminating boucle, mais je suis assez sûr qu'il ne sera pas dans mon cas.)

Le Tutoriel Java de Sun suggère ce n'est pas possible: "Notez qu' Iterator.remove est le seul moyen sûr de modifier une collection au cours d'une itération; le comportement est indéfini si la collection sous-jacente est modifié de quelque autre manière, tandis que l'itération est en cours."

Donc, si je ne peux pas faire ce que je veux faire à l'aide des itérateurs, que me conseillez-vous de faire?

67voto

Avi Points 14468

Comment à propos de la construction d'une File d'attente avec les éléments que vous souhaitez parcourir; si vous voulez ajouter des éléments, mise en file d'attente à la fin de la file d'attente, et de garder la suppression des éléments jusqu'à ce que la file d'attente est vide. C'est de cette manière en largeur d'abord de recherche travaille habituellement.

48voto

coobird Points 70356

Il y a deux problèmes ici:

La première question est, l'ajout d'un Collection après Iterator est retourné. Comme mentionné, il n'existe pas de comportement lorsque le sous-jacent Collection est modifié, comme indiqué dans la documentation pour l' Iterator.remove:

... Le comportement d'un itérateur est non spécifié si le sous-jacent la collection est modifiée alors que l' l'itération en cours, en quelque sorte d'autres que par l'appel de cette méthode.

Le deuxième problème est que, même si un Iterator pourrait être obtenu, et ensuite revenir à l'élément même de l' Iterator a été à l', il n'y a aucune garantie sur l'ordre de la iteratation, comme indiqué dans l' Collection.iterator documentation de la méthode:

... Il n'y a pas de garanties concernant la l'ordre dans lequel les éléments sont retournés (à moins que cette collection est une instance d'une classe qui fournit un la garantie).

Par exemple, disons que nous avons la liste [1, 2, 3, 4].

Disons - 5 a été ajoutée lors de l' Iterator a été à l' 3, et d'une certaine façon, nous obtenons un Iterator qui peut reprendre l'itération de l' 4. Cependant, il n'existe aucune garantie qu' 5 viendront après 4. L'itération de l'ordre peuvent être [5, 1, 2, 3, 4] -- puis l'itérateur va encore manquer l'élément 5.

Comme il n'y a aucune garantie pour le comportement, on ne peut pas présumer que les choses vont se passer d'une certaine manière.

Une alternative pourrait être d'avoir un Collection à laquelle le nouvellement créé éléments peuvent être ajoutés, puis une itération sur les éléments:

Collection<String> list = Arrays.asList(new String[]{"Hello", "World!"});
Collection<String> additionalList = new ArrayList<String>();

for (String s : list) {
    // Found a need to add a new element to iterate over,
    // so add it to another list that will be iterated later:
    additionalList.add(s);
}

for (String s : additionalList) {
    // Iterate over the elements that needs to be iterated over:
    System.out.println(s);
}

Modifier

L'élaboration de sur Avi, en réponse, il est possible de faire la queue les éléments que nous voulons parcourir dans une file d'attente, et de supprimer les éléments, tandis que la file d'attente a des éléments. Cela permettra à l' "itération" sur les nouveaux éléments en plus des éléments d'origine.

Voyons comment cela fonctionnerait.

Sur le plan conceptuel, si nous avons les éléments suivants dans la file d'attente:

[1, 2, 3, 4]

Et, quand on enlève 1, nous décidons d'ajouter 42, la file d'attente seront les suivantes:

[2, 3, 4, 42]

Comme la file d'attente est une FIFO (first-in, first-out) structure de données, ce classement est typique. (Comme indiqué dans la documentation de l' Queue interface, ce n'est pas une nécessité d'un Queue. Prenons le cas d' PriorityQueue qui trie les éléments par leur ordre naturel, ce qui n'est pas FIFO.)

L'exemple suivant est un exemple à l'aide d'un LinkedList (ce qui est une Queue) afin d'aller à travers tous les éléments le long avec des éléments supplémentaires ajoutés au cours de la dequeing. Similaire à l'exemple ci-dessus, l'élément 42 est ajouté lorsque l'élément 2 est supprimé:

Queue<Integer> queue = new LinkedList<Integer>();
queue.add(1);
queue.add(2);
queue.add(3);
queue.add(4);

while (!queue.isEmpty()) {
    Integer i = queue.remove();
    if (i == 2)
        queue.add(42);

    System.out.println(i);
}

Le résultat est le suivant:

1
2
3
4
42

Comme espéré, l'élément 42 qui a été ajouté lorsque nous avons touché 2 est apparu.

9voto

McDowell Points 62645

Vous pouvez également regarder une partie de la plus spécialisée de types, comme ListIterator, NavigableSet et (si vous êtes intéressé par des cartes) NavigableMap.

5voto

PatlaDJ Points 375

En fait, il est plutôt facile. Il suffit de penser de façon optimale. Je crois que la meilleure façon est:

for (int i=0; i<list.size(); i++) {
   Level obj = list.get(i);

   //Here execute yr code that may add / or may not add new element(s)
   //...

   i=list.indexOf(obj);
}

L'exemple suivant fonctionne parfaitement dans la logique de cas - lorsque vous n'avez pas besoin de parcourir les ajoute de nouveaux éléments avant l'itération de l'élément. Sur les éléments ajoutés après l'itération élément - là, vous pourriez ne pas réitérer ce soit. Dans ce cas, vous devez simplement ajouter/ou de prolonger an d'objet avec un drapeau qui les marquera à ne pas les réitérer.

1voto

javamonkey79 Points 6807

En utilisant les itérateurs...non, je ne le pense pas. Vous devrez hack ensemble quelque chose comme ceci:

	Collection< String > collection = new ArrayList< String >( Arrays.asList( "foo", "bar", "baz" ) );
	int i = 0;
	while ( i < collection.size() ) {

		String curItem = collection.toArray( new String[ collection.size() ] )[ i ];
		if ( curItem.equals( "foo" ) ) {
			collection.add( "added-item-1" );
		}
		if ( curItem.equals( "added-item-1" ) ) {
			collection.add( "added-item-2" );
		}

		i++;
	}

	System.out.println( collection );

Qui yeilds:
[foo, bar, baz, ajoute-item-1, ajouté-item-2]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X