Parfois, j'ai besoin de boucles qui nécessitent une pause comme celle-ci:
for(int i=0;i<array.length;i++){
//some other code
if(condition){
break;
}
}
Je me sens mal à l'aise avec l'écriture
if(condition){
break;
}
car il consomme 3 lignes de code. Et j'ai trouvé que la boucle peut être réécrite comme suit:
↓
for(int i=0;i<array.length && !condition;i++){
//some other code
}
Ma question est donc la suivante: est-ce une bonne pratique de déplacer la condition dans le champ de la condition afin de réduire les lignes de codes si possible?
coding-style
loops
ocomfd
la source
la source
condition
en particulier.for(int i=0;i<array.length && !condition;i++)
est relativement peu commune et peut être négligée par une personne qui ne fait que survoler le code; cela pourrait être un bon cas d'utilisation pour une bouclewhile
oudo while
, qui ont plus souvent plusieurs conditions de rupture dans la définition de la boucle.Réponses:
Ces deux exemples que vous avez donnés ne sont pas équivalents du point de vue fonctionnel. Dans l'original, le test de condition est effectué après la section "un autre code", alors que dans la version modifiée, il est effectué en premier, au début du corps de la boucle.
Le code ne doit jamais être réécrit dans le seul but de réduire le nombre de lignes. De toute évidence, c’est un avantage appréciable, mais cela ne devrait jamais se faire au détriment de la lisibilité ou de l’exactitude.
la source
Je n'achète pas l'argument selon lequel "cela consomme 3 lignes de code" et est donc mauvais. Après tout, vous pouvez simplement l'écrire comme suit:
et juste consommer une ligne.
Si le
if
symbole apparaît au milieu de la boucle, il doit bien sûr exister en tant que test séparé. Toutefois, si ce test apparaît à la fin du bloc, vous avez créé une boucle comportant un test de poursuite aux deux extrémités de la boucle, ce qui ajoute éventuellement à la complexité du code. Sachez cependant que parfois leif (condition)
test n'a de sens que lorsque le bloc a été exécuté.Mais en supposant que ce ne soit pas le cas, en adoptant l’autre approche:
les conditions de sortie sont maintenues ensemble, ce qui peut simplifier les choses (surtout si " un autre code " est long).
Il n'y a pas de bonne réponse ici bien sûr. Soyez donc conscient des idiomes de la langue, des conventions de codage de votre équipe, etc. Mais globalement, j'adopterais l'approche du test unique lorsqu'il est logique de le faire.
la source
Ce genre de question a suscité un débat presque aussi long que la programmation a été. Pour lancer mon chapeau dans le ring, je choisirais la version avec la
break
condition et voici pourquoi (dans ce cas particulier ):La
for
boucle est juste là pour spécifier les valeurs itératives dans la boucle. Le codage de la condition de rupture à l'intérieur de cela brouille la logique de l'OMI.Le fait d’avoir un séparateur
break
indique clairement que lors du traitement normal, les valeurs sont celles spécifiées dans lafor
boucle et que le traitement doit se poursuivre sauf là où la condition intervient.En guise d’arrière-plan, j’ai commencé à coder a
break
, puis j’ai mis la condition dans lafor
boucle pendant des années (sous la direction d’un programmeur exceptionnel), puis je suis revenu aubreak
style car il se sentait beaucoup plus propre (et c’était le style dominant les différents volumes de code que je consommais).C'est une autre de ces guerres saintes à la fin de la journée - certains disent que vous ne devriez jamais sortir d'une boucle artificiellement, sinon ce n'est pas une vraie boucle. Faites ce que vous jugez lisible (pour vous et pour les autres). Si réduire votre frappe est vraiment votre truc, allez jouer au golf le week-end - la bière est facultative.
la source
for
boucles sont utilisées lorsque le nombre d'itérations est connu (par exemple, lorsqu'il n'y a pas de condition de rupture, mais la fin du tableau / de la liste) etwhile
quand elles ne le sont pas. Cela semble être le cas pour unewhile
boucle. Si la lisibilité est le problème, l'idx+=1
intérieur de la boucle est beaucoup plus propre à lire qu'unif/else
blocfor(int i=0; i<something;i++)
boucles que je suppose que la moitié des développeurs ne se souviennent pas vraiment que lesfor
boucles peuvent être utilisées différemment, et ont donc du mal à comprendre la&&condition
partie.for(;;)
...for
les boucles sont pour une itération sur quelque chose 1 - elles ne sont pas simplement lol-tirons-quelque-chose-au-hasard-du-corps-et-les-mettent-dans-la-tête-boucle - les trois expressions ont très significations spécifiques:L'idée est de séparer la gestion des itérations ( comment effectuer une itération) de la logique à l'intérieur de la boucle ( que faire à chaque itération). De nombreuses langues ont généralement une boucle for-each qui vous évite les détails de l'itération, mais même si votre langue n'a pas cette construction, ou si elle ne peut pas être utilisée dans votre scénario, vous devez toujours limiter l'en-tête de la boucle. à la manipulation d'itération.
Vous devez donc vous poser la question suivante: votre état est-il lié au traitement des itérations ou à la logique dans la boucle? Les chances sont, il s'agit de la logique à l'intérieur de la boucle - donc il devrait être vérifié à l'intérieur de la boucle plutôt que dans l'en-tête.
1 Contrairement aux autres boucles, cela "attend" que quelque chose se passe. Une boucle
for
/foreach
devrait avoir le concept d'une "liste" d'éléments sur lesquels itérer, même si cette liste est paresseuse ou infinie ou abstraite.la source
someFunction(array[i])
. Maintenant, les deux parties de la condition concernent la chose sur laquelle vous effectuez une itération et il serait logique de les combiner&&
dans l'en-tête de la boucle.for
boucles au coeur sont des compteurs, pas des boucles sur une liste, et ceci est supporté par la syntaxe defor
dans les langages précédents (ces langages avaient souvent unefor i = 1 to 10 step 2
syntaxe, et lastep
commande - permettant même une valeur initiale qui ne soit pas l'index du élément - indique un contexte numérique, pas un contexte de liste). Le seul cas d'utilisation qui, à mon avis,for
prenne en charge les boucles car il suffit d'itérer une liste, c'est la parallélisation, ce qui nécessite de toute façon une syntaxe explicite pour ne pas altérer le code, par exemple, une sorte.Je recommande d'utiliser la version avec
if (condition)
. C'est plus lisible et plus facile à déboguer. L'écriture de 3 lignes de code supplémentaires ne vous cassera pas les doigts, mais facilitera la compréhension du code par la prochaine personne.la source
naming things
afin de comprendre ce qui se passe et quand la condition de rupture est remplie.Si vous parcourez une collection où certains éléments doivent être ignorés, je vous recommande une nouvelle option:
Java et C # rendent cela relativement facile à faire. Je ne serais pas surpris si C ++ avait le moyen de créer un itérateur de fantaisie pour ignorer certains éléments qui ne s'appliquent pas. Mais ce n'est vraiment une option que si votre langue de choix le supporte, et la raison que vous utilisez
break
est parce qu'il existe des conditions pour que vous traitiez un élément ou non.Sinon, il existe une très bonne raison de faire de votre condition une partie de la boucle for - en supposant que l'évaluation initiale soit correcte.
J'ai travaillé sur du code où votre boucle for prend quelques centaines de lignes avec plusieurs conditions et quelques calculs complexes s'y déroulant. Les problèmes que vous rencontrez avec ceci sont:
break
les commandes enfouies dans la logique sont difficiles à trouver et parfois surprenantesDans cette situation, je recommande les directives suivantes par ordre de préférence:
break
si possiblebreak
en haut de la boucle si possibleCes instructions sont toujours sujettes à l' exactitude de votre code. Choisissez l'option qui représente le mieux l'intention et améliore la clarté de votre code.
la source
continue
déclarations, mais je ne vois pas en quoi elles aident beaucoupbreak
.takeWhile
filtre peut remplacer desbreak
instructions. Si vous en avez un - Java, par exemple, ne les obtient que lors de la Jave 9 (non que ce soit si difficile à mettre en œuvre vous-même)Je recommande fortement d’adopter l’approche de la moindre surprise à moins d’obtenir un avantage significatif en agissant autrement.
Les gens ne lisent pas chaque lettre en lisant un mot et ne lisent pas chaque mot en lisant un livre. S'ils sont des adeptes de la lecture, ils regardent les contours des mots et des phrases et laissent leur cerveau remplir le reste. .
Il est donc probable qu'un développeur occasionnel présumera qu'il ne s'agit que d'une norme pour la boucle et ne la regarde même pas:
Si vous voulez utiliser ce style, peu importe, je vous recommande de changer les parties
for(int i=0;i<
et d';i++)
indiquer au cerveau du lecteur qu'il s'agit d'un standard pour la boucle.Une autre raison d'aller avec
if
-break
est que vous ne pouvez pas toujours utiliser votre approche avec lefor
-état. Vous devez utiliserif
-break
lorsque la condition de rupture est trop complexe pour être masquée dans unefor
instruction ou repose sur des variables uniquement accessibles à l'intérieur de lafor
boucle.Donc, si vous décidez d'aller avec
if
-break
, vous êtes couvert. Mais si vous décidez d'aller avecfor
-Conditions, vous devez utiliser un mélange deif
-break
etfor
-Conditions. Pour être cohérent, vous devez déplacer les conditions dans les deux sens entre lesfor
-Conditions etif
- àbreak
chaque fois que les conditions changent.la source
Votre transformation suppose que tout ce qui
condition
est évalué se produittrue
lorsque vous entrez dans la boucle. Nous ne pouvons pas commenter sur la justesse de cela dans ce cas car il n'est pas défini.Après avoir réussi à "réduire les lignes de code" ici, vous pouvez ensuite regarder
et appliquer la même transformation, arriver à
Ce qui est une transformation invalide, comme vous le faites maintenant sans condition
further code
.Un schéma de transformation beaucoup plus sûr consiste à extraire
some other code
et à évaluercondition
une fonction distinctela source
TL; DR Faites ce qui se lit le mieux dans votre cas particulier
Prenons cet exemple:
Dans ce cas, nous ne souhaitons pas que le code de la boucle for s'exécute si la valeur
something
est true, le déplacement du test desomething
dans le champ de condition est donc raisonnable.Là encore, en fonction de si
something
peut être définitrue
avant la boucle, mais pas au sein de celle-ci, cela pourrait offrir plus de clarté:Maintenant, imaginez ceci:
Nous envoyons un message très clair là-bas. Si
something
devient vrai pendant le traitement de la matrice, abandonnez alors toute l'opération à ce stade. Afin de déplacer le contrôle dans le champ de condition, vous devez effectuer les tâches suivantes:On peut soutenir que le "message" est devenu flou et que nous vérifions la condition de panne à deux endroits - que se passera-t-il si la condition de panne change et que nous en oublions un?
Il existe bien sûr beaucoup plus de formes différentes qu'une boucle ou une condition pourrait être, toutes avec leurs propres nuances.
Écrivez le code pour qu'il se lise bien (ceci est évidemment quelque peu subjectif) et de manière concise. En dehors d'un ensemble draconien de directives de codage, toutes les "règles" ont des exceptions. Ecrivez ce que vous pensez exprimer le mieux la prise de décision et minimisez les risques d'erreurs futures.
la source
Bien que cela puisse sembler attrayant, car vous voyez toutes les conditions dans l’en-tête de la boucle et
break
peut prêter à confusion à l’intérieur de grands blocs, unefor
boucle est un motif dans lequel la plupart des programmeurs s’attendent à une boucle sur une certaine plage.Surtout depuis que vous le faites, l'ajout d'une condition de rupture supplémentaire peut entraîner une confusion et il est plus difficile de voir si elle est fonctionnellement équivalente.
Une bonne solution consiste souvent à utiliser une boucle
while
oudo {} while
qui vérifie les deux conditions, en supposant que votre tableau comporte au moins un élément.En utilisant une boucle qui ne fait que vérifier une condition et ne pas exécuter de code à partir de l'en-tête de la boucle, vous êtes très clair lorsque la condition est vérifiée, quelle est la condition réelle et quel est le code avec les effets secondaires.
la source
for(...; i <= n; ...)
) rend le code plus difficile à lire car j'ai s'arrêter et réfléchir à ce qui se passe ici et pourrait manquer la condition lors du premier passage parce que je ne m'attends pas à ce qu'il soit là. Pour moi, unefor
boucle implique que vous boucliez sur une plage. S'il existe une condition de sortie spéciale, elle doit être explicite avec unif
, ou vous pouvez utiliser unwhile
.C'est mauvais, car le code est destiné à être lu par des humains - les
for
boucles non idiomatiques sont souvent difficiles à lire, ce qui signifie que les bogues se cachent plus facilement ici, mais le code original aurait pu être amélioré tout en le maintenant. court et lisible.Si vous souhaitez rechercher une valeur dans un tableau (l'exemple de code fourni est quelque peu générique, mais il peut aussi s'agir de ce modèle), vous pouvez simplement essayer explicitement d'utiliser une fonction fournie par un langage de programmation spécifiquement à cette fin. Par exemple (pseudo-code, car un langage de programmation n'a pas été spécifié, les solutions varient en fonction d'un langage particulier).
Cela devrait sensiblement raccourcir la solution tout en la simplifiant, car votre code indique précisément ce dont vous avez besoin.
la source
À mon avis, peu de raisons disent que vous ne devriez pas.
do...while
boucle (paswhile
) car la condition est vérifiée après une exécution de code.Mais en plus de cela, considérez ceci,
Maintenant, pouvez-vous vraiment y arriver en ajoutant ces conditions à cette
for
condition?la source
Je pense que supprimer le
break
peut être une bonne idée, mais pas pour sauvegarder des lignes de code.L'avantage de l'écrire sans cela
break
est que la post-condition de la boucle est évidente et explicite. Lorsque vous terminez la boucle et exécutez la ligne suivante du programme, votre condition de bouclei < array.length && !condition
doit être fausse. Par conséquent, soiti
était supérieur ou égal à votre longueur de tableau, oucondition
est true.Dans la version avec
break
, il y a un piège caché. La condition de boucle indique que la boucle se termine lorsque vous avez exécuté un autre code pour chaque index de tableau valide, mais il existe en fait unebreak
instruction qui pourrait terminer la boucle avant, et vous ne la verrez pas à moins de consulter le code de la boucle. très soigneusement. Et les analyseurs statiques automatisés, y compris l'optimisation des compilateurs, pourraient également avoir du mal à déterminer quelles sont les conditions postérieures de la boucle.C'est la raison pour laquelle Edgar Dijkstra a écrit «Goto Considered Harmful». Ce n'était pas une question de style: rompre avec une boucle empêche de raisonner formellement sur l'état du programme. J'ai écrit beaucoup de
break;
déclarations dans ma vie, et une fois adulte, j'ai même écrit ungoto
(pour sortir de plusieurs niveaux d'une boucle interne de performances critiques puis pour continuer avec une autre branche de l'arbre de recherche). Cependant, je suis beaucoup plus susceptible d'écrire unereturn
instruction conditionnelle à partir d'une boucle (qui n'exécute jamais le code après la boucle et ne peut donc pas en vider ses post-conditions) qu'unbreak
.Postscript
En fait, refactoriser le code pour obtenir le même comportement pourrait nécessiter davantage de lignes de code. Votre refactoring pourrait être valable pour un autre code ou si nous pouvons prouver que
condition
cela commencera faux. Mais votre exemple équivaut dans le cas général à:Si un autre code ne correspond pas à une ligne, vous pouvez le déplacer vers une fonction afin de ne pas vous répéter, puis vous avez presque transformé votre boucle en une fonction récursive.
Je reconnais toutefois que ce n’était pas l’essentiel de votre question et que vous restiez simple.
la source
break
énoncé, vous savez alors quelle est la condition de boucle et que la boucle s'arrête lorsque cette condition est fausse. S'il y en abreak
? Ensuite, la boucle peut se terminer de plusieurs façons et, dans le cas général, déterminer quand l'un d'entre eux pourrait arrêter la boucle résout littéralement le problème de la suppression. En pratique, ce qui me préoccupe le plus, c’est que la boucle ressemble à une chose, mais en réalité, quiconque a écrit le code après la boucle a négligé un cas périphérique enterré dans une logique complexe. Il est difficile de rater des choses dans la boucle.Oui, mais votre syntaxe est non conventionnelle et donc mauvaise (tm)
Espérons que votre langue supporte quelque chose comme
la source
while
met l'accent sur le monstre dans le code - l'exception cachée dans le code de routine / ordinaire. La logique métier est à l'avant-plan, la mécanique de bouclage est comprise. Cela évite la réaction "attendez une minute ..." à l'for
alternative boucle. Cette réponse corrige le problème. vote absolument.Si vous craignez qu'une
for
déclaration trop complexe soit difficile à lire, c'est certainement une préoccupation valable. Le gaspillage d'espace vertical est également un problème (bien que moins critique).(Personnellement, je n'aime pas la règle
if
selon laquelle les instructions doivent toujours avoir des accolades, ce qui est en grande partie la cause de l'espace vertical gaspillé ici. Notez que le problème est de gaspiller de l'espace vertical. L' utilisation d' un espace vertical avec des lignes significatives ne devrait pas poser de problème.)Une option consiste à le scinder en plusieurs lignes. C’est certainement ce que vous devriez faire si vous utilisez des
for
instructions très complexes , avec plusieurs variables et conditions. (C’est pour moi une meilleure utilisation de l’espace vertical, donnant à autant de lignes que possible quelque chose de significatif.)Une meilleure approche pourrait être d’essayer d’utiliser une forme plus déclarative et moins impérative. Cela varie en fonction de la langue. Vous devrez peut-être écrire vos propres fonctions pour activer ce type de choses. Cela dépend aussi de ce
condition
qui est réellement. Vraisemblablement, il doit pouvoir changer d’une manière ou d’une autre, en fonction de ce qui se trouve dans le tableau.la source
for
déclaration complexe ou inhabituelle en plusieurs lignes est la meilleure idée de toute cette discussionUne chose qui a été oubliée: lorsque je sors d'une boucle (je ne fais pas toutes les itérations possibles, peu importe son implémentation), c'est généralement le cas. Non seulement je veux sortir de la boucle, mais je veux aussi savoir pourquoi c'est arrivé. . Par exemple, si je cherche un élément X, non seulement je casse la boucle, mais je veux aussi savoir que X a été trouvé et où il se trouve.
Dans cette situation, avoir une condition en dehors de la boucle est tout à fait naturel. Donc je commence avec
et dans la boucle j'écrirai
avec la boucle for
Maintenant, vérifier l'état de la boucle est assez naturel. L'existence d'une instruction "break" dépend de la nature du traitement que vous souhaitez éviter dans la boucle. Si un traitement est nécessaire et que ce n’est pas le cas, vous pouvez avoir quelque chose comme:
quelque part dans votre boucle.
la source