Dentro de um loop for, devo mover a condição de interrupção para o campo de condição, se possível? [fechadas]


48

Às vezes eu preciso de loops que precisam de uma pausa como esta:

for(int i=0;i<array.length;i++){
    //some other code
    if(condition){
        break;
    }
}

Eu me sinto desconfortável com a escrita

if(condition){
    break;
}

porque consome 3 linhas de código. E descobri que o loop pode ser reescrito como:

                                   ↓
for(int i=0;i<array.length && !condition;i++){
    //some other code
}

Portanto, minha pergunta é: é uma boa prática mover a condição para o campo de condição para reduzir linhas de códigos, se possível?


7
Depende do que conditioné em particular.
Bergi

4
Há uma razão pela qual o misra proíbe o uso de "break" e "continue" dentro de loops. Veja também este: stackoverflow.com/q/3922599/476681
BЈовић

35
Eu acho que o número de linhas em si não é o problema real. Pode ser escrito em uma linha. se (condição) quebrar; A questão na minha opinião é legibilidade. Pessoalmente, não gosto de quebrar um loop que não seja a condição do loop.
31418 Joe

97
porque consome 3 linhas de código. Uma razão muito, muito, muito ruim para não gostar de nenhum estilo. A IMO "consumindo [linhas] de código" está entre algo irrelevante e bom. Tentar inserir muita lógica em poucas linhas resulta em código ilegível e erros difíceis de encontrar.
Andrew Henle

3
Opinião possivelmente impopular: for(int i=0;i<array.length && !condition;i++)é relativamente incomum e pode ser negligenciada por alguém que apenas está analisando o código; esse pode ser um bom caso de uso para um loop whileou do while, que geralmente possui várias condições de interrupção na definição do loop.
Jules

Respostas:


154

Esses dois exemplos que você deu não são funcionalmente equivalentes. No original, o teste de condição é realizado após a seção "algum outro código", enquanto na versão modificada, é feito primeiro, no início do corpo do loop.

O código nunca deve ser reescrito com o único objetivo de reduzir o número de linhas. Obviamente, é um bom bônus quando funciona dessa maneira, mas nunca deve ser feito à custa da legibilidade ou correção.


5
Entendo sua opinião, mas mantive código legado suficiente, em que o loop tem várias centenas de linhas e há várias quebras condicionais. Isso torna a depuração muito difícil quando você espera que o código chegue à quebra condicional que você espera, mas o código anterior exerceu sua quebra condicional primeiro. Como você lida com esse código? Em breves exemplos como o acima, é fácil esquecer esse tipo de cenário muito comum.
Berin Loritsch

84
@BerinLoritsch: A maneira correta de lidar com isso é não ter loops com várias centenas de linhas!
27418 Chris

27
@ Walfrat: Se reescrever, não é uma opção, então não há mais uma pergunta. Dito isto, você geralmente pode usar com segurança um refator do tipo "Extrair método" para mover blocos de código, o que deve reduzir o loop do método principal e, com sorte, tornar a lógica fluir mais óbvia. É realmente uma coisa caso a caso. Eu vou manter minha regra geral de manter os métodos curtos e, definitivamente, manter a lógica do loop próximo, mas não quero tentar dizer mais do que isso em termos gerais ...
Chris

4
A brevidade do @AndrewHenle é legibilidade, pelo menos no sentido de que o aumento da verbosidade sempre reduz a legibilidade e a capacidade de manutenção. A redução do LOC é alcançada aumentando a densidade e aumentando o nível de abstração e está fortemente correlacionada com a capacidade de manutenção, conforme atestado em outros pares de perguntas / respostas neste mesmo local.
Leushenko 28/02

5
@ A construção Joe-Do-While é tão rara que é propensa a criar desenvolvedores que precisam manter esse código mais tarde. Alguns desenvolvedores nunca os viram! Não tenho certeza se um tempo de folga melhoraria a legibilidade - se houver, aumentaria a dificuldade de entender o código. Apenas como exemplo - minha base de código atual tem cerca de 15 anos e cerca de 2 milhões de LOC. Cerca de cinquenta desenvolvedores já o tocaram. Ele tem exatamente zero loops de tempo de atividade!
T. Sar - Restabelece Monica

51

Eu não compro o argumento de que "consome 3 linhas de código" e, portanto, é ruim. Afinal, você pode escrever como:

if (condition) break;

e consuma apenas uma linha.

Se ele ifaparecer na metade do loop, é claro que deve existir como um teste separado. No entanto, se esse teste aparecer no final do bloco, você criou um loop que possui um teste contínuo nas duas extremidades do loop, possivelmente aumentando a complexidade do código. Esteja ciente de que, às vezes, o if (condition)teste só faz sentido após a execução do bloco.

Mas supondo que não seja esse o caso, adotando a outra abordagem:

for(int i=0;i<array.length && !condition;i++){
    //some other code
}

as condições de saída são mantidas juntas, o que pode simplificar as coisas (especialmente se " algum outro código " for longo).

Não há resposta certa aqui, é claro. Portanto, esteja ciente das expressões idiomáticas da linguagem, quais são as convenções de codificação de sua equipe etc.


14
@ jpmc26, melhor? Não. Estilo alternativo válido? Claro.
David Arno

6
Melhor como é mais difícil de estragar quando o código é editado mais tarde, e não sofre nenhuma desvantagem notável.
Jpmc26

4
Mantê-los juntos por causa do "conteúdo do loop pode ser longo" parece ser um argumento fraco. Quando seu conteúdo for difícil de ler, você tem outros problemas além de salvar as duas linhas de código.
BlueWizard 27/02

12
@ jpmc26 Discordo. Os aparelhos são desordenados supérfluos nos condicionais mais curtos e de uma linha, de acordo com esta resposta. Sem é mais elegante e mais fácil para os olhos. Eles são como um operador condicional ternário. Nunca me esqueci de adicionar os aparelhos ao dividi-los em blocos de instruções maiores; Eu já estou adicionando novas linhas, afinal.
benxyzzy

3
É tudo uma preferência de estilo, mas se alguém argumentar que é mais seguro, eu discordaria desse raciocínio. Eu prefiro sem chaves e na próxima linha, mas isso não significa que é mais ou menos válida do que outros estilos
phflack

49

Esse tipo de pergunta provocou debates quase tanto quanto a programação. Para jogar meu chapéu no ringue, eu iria para a versão com a breakcondição e aqui está o porquê (neste caso específico ):

O forloop está lá apenas para especificar os valores de iteração no loop. Codificar a condição de interrupção dentro da qual apenas atrapalha a lógica IMO.

Ter um separador breakdeixa claro que, durante o processamento normal, os valores são os especificados no forloop e o processamento deve continuar, exceto onde a condição entrar.

Como pano de fundo, comecei a codificar a break, depois coloquei a condição no forloop por anos (sob a direção de um programador excepcional) e depois voltei ao breakestilo porque parecia muito mais limpo (e era o estilo predominante em os vários volumes de código que eu estava consumindo).

É outra daquelas guerras sagradas no final do dia - alguns dizem que você nunca deve sair artificialmente de um loop, caso contrário, não é um loop real. Faça o que achar que é legível (tanto para você quanto para os outros). Se reduzir o pressionamento de teclas é realmente o seu lugar, vá jogar código no fim de semana - cerveja opcional.


3
Se a condição tiver um bom nome, como "encontrado" (por exemplo, você está procurando alguma coisa na matriz), é uma boa ideia colocá-la na cabeça do loop for.
user949300

11
Foi-me dito que os forloops são usados ​​quando o número de iterações é conhecido (por exemplo, quando não há condição de interrupção, mas o final da matriz / lista) e whilequando não são. Este parece ser o caso de um whileloop. Se a leitura é a preocupação de idx+=1dentro do loop é muito mais limpo para ler do que um if/elsebloco
LAIV

Você não pode simplesmente colocar a condição de interrupção no loop se houver código a seguir, portanto, pelo menos, você teria que escrever "if (condition) {found = true; continue;} #
gnasher729

Estamos tão acostumados com for(int i=0; i<something;i++)loops que acho que metade dos desenvolvedores realmente não se lembra que os forloops podem ser usados ​​de maneira diferente e, portanto, têm dificuldade em entender a &&conditionparte.
Ralf Kleberhoff

@RalfKleberhoff De fato. Eu já vi muitos desenvolvedores expressarem surpresa por as expressões tripart da instrução serem opcionais. Eu nem me lembro a última vez que eu vi for(;;)...
Robbie Dee

43

forloops são para iteração sobre algo 1 - eles não são apenas lol-vamos-puxar-algumas-coisas-aleatórias-do-corpo-e-colocá-los-no-loop-cabeçalho - as três expressões têm muito significados específicos:

  • O primeiro é para inicializar o iterador . Pode ser um índice, um ponteiro, um objeto de iteração ou qualquer outra coisa - desde que seja usado para iteração .
  • O segundo é para verificar se chegamos ao fim.
  • O terceiro é para avançar o iterador.

A idéia é separar o tratamento da iteração ( como iterar) da lógica dentro do loop ( o que fazer em cada iteração). Geralmente, muitos idiomas têm um loop for-each que libera você dos detalhes da iteração, mas mesmo que seu idioma não tenha essa construção ou se não puder ser usado no seu cenário - você ainda deve limitar o cabeçalho do loop para manipulação de iteração.

Então, você precisa se perguntar - sua condição é sobre o tratamento da iteração ou sobre a lógica dentro do loop? As chances são de que se trata da lógica dentro do loop - portanto, ele deve ser verificado dentro do loop e não no cabeçalho.

1 Ao contrário de outros loops, que estão "esperando" que algo aconteça. Um loop for/ foreachdeve ter o conceito de uma "lista" de itens para iterar - mesmo que essa lista seja lenta, infinita ou abstrata.


5
Este foi o meu primeiro pensamento quando li a pergunta. Desapontado que eu tinha que percorrer meia dúzia de respostas para ver alguém dizer isso
Nemo

4
Umm ... todos os loops são para iteração - é isso que a palavra "iteração" significa :-). Suponho que você queira dizer algo como "iterando sobre uma coleção" ou "iterando usando um iterador"?
Psmears 27/02

3
@psmears OK, talvez eu tenha escolhido a palavra errada - o inglês não é minha língua nativa e, quando penso na iteração, penso em "iteração sobre alguma coisa". Eu vou consertar a resposta.
Idan Arye 27/02

Um caso intermediário é onde a condição é semelhante someFunction(array[i]). Agora, ambas as partes da condição são sobre o assunto sobre o qual você está iterando e faria sentido combiná-las &&no cabeçalho do loop.
Barmar 28/02

Eu respeito sua posição, mas discordo. Eu acho que forloops no coração são contadores, não loops em uma lista, e isso é suportado pela sintaxe de foridiomas anteriores (esses idiomas geralmente tinham uma for i = 1 to 10 step 2sintaxe e o stepcomando - mesmo permitindo um valor inicial que não é o índice do primeiro elemento - sugere um contexto numérico, não um contexto de lista). O único caso de uso que eu acho que suporta forloops apenas como iterativo em uma lista é paralelo, e isso requer sintaxe explícita agora de qualquer maneira para não quebrar o código, por exemplo, uma classificação.
Logan Captura

8

Eu recomendo usar a versão com if (condition). É mais legível e mais fácil de depurar. Escrever três linhas extras de código não quebrará os dedos, mas facilitará a compreensão da sua próxima pessoa.


11
Somente se (como foi comentado) o bloco de loop não tiver centenas de linhas de código e a lógica interna não for ciência do foguete. Acho que seu argumento está naming thingscorreto , mas sinto falta de algo como corretamente para entender o que está acontecendo e quando a condição de quebra é atendida.
28418 Laiv

2
@Laiv Se o bloco de loop tiver centenas de linhas de código, haverá problemas maiores do que a questão de onde escrever a condição de quebra.
Aleksander

Foi por isso que sugeri contextualizar a resposta, porque nem sempre é verdade.
28418 Laiv

8

Se você estiver repetindo uma coleção em que certos elementos devem ser ignorados, recomendo uma nova opção:

  • Filtre sua coleção antes de iterar

Java e C # tornam isso relativamente trivial. Não ficaria surpreso se o C ++ tivesse uma maneira de criar um iterador sofisticado para pular certos elementos que não se aplicam. Mas isso só é realmente uma opção se a sua linguagem de escolha a suportar, e a razão pela qual você está usando breaké porque existem condições para processar ou não um elemento.

Caso contrário, há uma boa razão para tornar sua condição parte do loop for - supondo que a avaliação inicial esteja correta.

  • É mais fácil ver quando um loop termina mais cedo

Eu trabalhei no código em que seu loop for leva algumas centenas de linhas com vários condicionais e algumas matemáticas complexas acontecendo lá. Os problemas com os quais você se depara são:

  • break comandos escondidos na lógica são difíceis de encontrar e às vezes surpreendentes
  • A depuração requer percorrer cada iteração do loop para entender realmente o que está acontecendo
  • Muito do código não possui refatorações facilmente reversíveis disponíveis ou testes de unidade para ajudar na equivalência funcional após uma reescrita

Nessa situação, recomendo as seguintes diretrizes em ordem de preferência:

  • Filtre a coleção para eliminar a necessidade de um, breakse possível
  • Tornar a parte condicional das condições do loop for
  • Coloque os condicionais com breakno topo do loop, se possível
  • Adicione um comentário de várias linhas chamando a atenção para o intervalo e por que ele está lá

Essas diretrizes estão sempre sujeitas à correção do seu código. Escolha a opção que melhor possa representar a intenção e melhorar a clareza do seu código.


11
A maior parte dessa resposta está correta. Mas ... vejo como a filtragem de uma coleção pode eliminar a necessidade de continueinstruções, mas não vejo como elas ajudam muito break.
user949300

11
@ user949300 Um takeWhilefiltro pode substituir breakinstruções. Se você tiver um - Java, por exemplo, só recebe-los em Jave 9 (não que é que difícil de implementar it yourself)
Idan Arye

11
Mas em Java você ainda pode filtrar antes da iteração. Usando fluxos (1.8 ou posterior) ou usando Apache Collections (1.7 ou anterior).
28418 Laiv

@IdanArye - existem bibliotecas de complementos que adicionam esses recursos à API de fluxos Java (por exemplo, JOO-lambda ) #
317

@IdanArye nunca ouviu falar de um takeWhile antes do seu comentário. Vincular explicitamente o filtro a um pedido me parece incomum e hacky, já que em um filtro "normal" todo elemento retorna verdadeiro ou falso, independentemente do que vem antes ou depois. Dessa forma, você pode executar as coisas em paralelo.
user949300

8

Eu recomendo fortemente adotar a abordagem da menor surpresa, a menos que você obtenha um benefício significativo fazendo o contrário.

As pessoas não leem todas as letras ao ler uma palavra e não lêem todas as palavras ao ler um livro - se são adeptos da leitura, olham os contornos das palavras e frases e deixam o cérebro preencher o resto .

Portanto, é provável que um desenvolvedor ocasional assuma que isso é apenas um padrão para loop e nem sequer veja:

for(int i=0;i<array.length&&!condition;i++)

Se você deseja usar esse estilo de qualquer maneira, recomendo alterar as partes for(int i=0;i<e ;i++)informar ao cérebro do leitor que esse é um padrão para loop.


Outro motivo para seguir com if- breaké que você nem sempre pode usar sua abordagem com a forcondição -. Você precisa usar if- breakquando a condição de interrupção é muito complexa para se esconder dentro de uma forinstrução ou depende de variáveis ​​acessíveis apenas dentro do forloop.

for(int i=0;i<array.length&&!((someWidth.X==17 && y < someWidth.x/2) || (y == someWidth.x/2 && someWidth.x == 18);i++)

Então, se você decidir ir com if- break, estará coberto. Mas se você optar por usar for-conditions, precisará usar uma combinação de if- breake for-conditions. Para ser consistente, você precisará mover as condições para frente e para trás entre as forcondições e o if- breaksempre que as condições mudarem.


4

Sua transformação está assumindo que tudo o que conditioné avaliado é truequando você entra no loop. Não podemos comentar sobre a correção disso neste caso, porque não está definido.

Tendo conseguido "reduzir linhas de código" aqui, você pode então continuar olhando

for(int i=0;i<array.length;i++){
    // some other code
    if(condition){
        break;
    }
    // further code
}

e aplique a mesma transformação, chegando a

for(int i=0;i<array.length && !condition;i++){
    // some other code
    // further code
}

O que é uma transformação inválida, como você agora faz incondicionalmente further codeonde não fazia anteriormente.

Um esquema de transformação muito mais seguro é extrair some other codee avaliar conditionpara uma função separada

bool evaluate_condition(int i) // This is an horrible name, but I have no context to improve it
{
     // some other code
     return condition;
}

for(int i=0;i<array.length && !evaluate_condition(i);i++){
    // further code
}

4

TL; DR Faça o que for melhor em sua circunstância específica

Vamos pegar este exemplo:

for ( int i = 1; i < array.length; i++ ) 
{
    if(something) break;
    // perform operations
}

Nesse caso, não queremos que nenhum código do loop for somethingseja executado se for verdadeiro, portanto, mover o teste de somethingpara o campo de condição é razoável.

for ( int i = 1; i < array.length && !something; i++ )

Então, novamente, dependendo de se somethingpode ser definido como trueantes do loop, mas não dentro dele, isso pode oferecer mais clareza:

if(!something)
{
    for ( int i = 1; i < array.length; i++ )
    {...}
}

Agora imagine isso:

for ( int i = 1; i < array.length; i++ ) 
{
    // perform operations
    if(something) break;
    // perform more operations
}

Estamos enviando uma mensagem muito clara lá. Se somethingfor verdadeiro durante o processamento da matriz, abandone toda a operação neste momento. Para mover a verificação para o campo de condição, você precisa:

for ( int i = 1; i < array.length && !something; i++ ) 
{
    // perform operations
    if(!something)
    {
        // perform more operations
    }
}

Indiscutivelmente, a "mensagem" ficou turva, e estamos verificando a condição de falha em dois lugares - e se a condição de falha mudar e esquecermos um desses lugares?

É claro que existem muitas outras formas diferentes que um loop e uma condição poderiam ser, todas com suas próprias nuances.

Escreva o código para que ele leia bem (isso é obviamente um pouco subjetivo) e concisa. Fora de um conjunto draconiano de diretrizes de codificação, todas as "regras" têm exceções. Escreva o que você acha que expressa melhor a tomada de decisão e minimize as chances de erros futuros.


2

Embora possa ser atraente porque você vê todas as condições no cabeçalho do loop e breakpode ser confuso dentro de blocos grandes, um forloop é um padrão no qual a maioria dos programadores espera loop em algum intervalo.

Especialmente desde que você faz isso, adicionar uma condição de interrupção adicional pode causar confusão e é mais difícil ver se é funcionalmente equivalente.

Geralmente, uma boa alternativa é usar um loop whileou do {} whileque verifica as duas condições, assumindo que sua matriz tenha pelo menos um elemento.

int i=0
do {
    // some other code
    i++; 
} while(i < array.length && condition);

Usando um loop que apenas verifica uma condição e não executa o código no cabeçalho do loop, você deixa muito claro quando a condição é verificada e qual é a condição real e qual é o código com efeitos colaterais.


Apesar de essa pergunta já ter boas respostas, eu gostaria de vomitar isso especificamente porque faz um ponto importante: para mim, ter algo além de uma simples verificação vinculada no loop for ( for(...; i <= n; ...)) torna o código mais difícil de ler porque eu tenho parar e pensar no que está acontecendo aqui e pode perder completamente a condição na primeira passagem, porque não espero que ela esteja lá. Para mim, um forloop implica que você está fazendo um loop em algum intervalo; se houver uma condição de saída especial, ele deve ser explicitado com um if, ou você pode usar um while.
CompuChip 28/02

1

Isso é ruim, pois o código deve ser lido pelos seres humanos - forloops não-idiomáticos geralmente são confusos de ler, o que significa que os bugs provavelmente estão escondidos aqui, mas o código original pode ter sido possível melhorar, mantendo os dois curto e legível.

Se o que você deseja é encontrar um valor em uma matriz (a amostra de código fornecida é um pouco genérica, mas também pode ser esse padrão), tente explicitamente apenas usar uma função fornecida por uma linguagem de programação especificamente para esse fim. Por exemplo (pseudocódigo, como uma linguagem de programação não foi especificada, as soluções variam dependendo de uma linguagem específica).

array.find(item -> item.valid)

Isso deve reduzir visivelmente a solução, simplificando-a, pois seu código diz especificamente o que você precisa.


1

Na minha opinião, poucas razões dizem que você não deveria.

  1. Isso reduz a legibilidade.
  2. A saída pode não ser a mesma. No entanto, isso pode ser feito com um do...whileloop (não while), pois a condição é verificada após alguma execução do código.

Mas, além disso, considere isso,

for(int i=0;i<array.length;i++){

    // Some other code
    if(condition1){
        break;
    }

    // Some more code
    if(condition1){
        break;
    }

    // Some even more code
}

Agora, você pode realmente alcançá-lo adicionando essas condições a essa forcondição?


O que é " abertura "? Você quer dizer " opinião "?
Peter Mortensen

O que você quer dizer com "Poucas razões na abertura que dizem que você não deveria" ? Você pode elaborar?
Peter Mortensen

0

Eu acho que remover o breakpode ser uma boa idéia, mas não salvar linhas de código.

A vantagem de escrevê-lo sem breaké que a pós-condição do loop é óbvia e explícita. Quando você termina o loop e executa a próxima linha do programa, sua condição do loop i < array.length && !conditiondeve ter sido falsa. Portanto, iera maior ou igual ao comprimento da matriz ou conditioné verdadeiro.

Na versão com break, há uma pegadinha oculta. A condição do loop diz que o loop termina quando você executa outro código para cada índice de matriz válido, mas na verdade existe uma breakinstrução que poderia terminar o loop antes disso e você não a verá a menos que revise o código do loop muito cuidado. E os analisadores estáticos automatizados, incluindo a otimização de compiladores, também podem ter problemas para deduzir quais são as pós-condições do loop.

Essa foi a razão original pela qual Edgar Dijkstra escreveu “Goto Considerado Prejudicial”. Não era uma questão de estilo: sair de um círculo dificulta a formalidade de raciocinar sobre o estado do programa. Escrevi muitas break;declarações em minha vida e, uma vez adulto, até escrevi um goto(para romper com vários níveis de um loop interno crítico para o desempenho e continuar com outro ramo da árvore de pesquisa). No entanto, tenho muito mais probabilidade de escrever uma returndeclaração condicional a partir de um loop (que nunca executa o código após o loop e, portanto, não pode estragar suas pós-condições) do que a break.

Postscript

De fato, refatorar o código para fornecer o mesmo comportamento pode realmente precisar de mais linhas de código. Sua refatoração pode ser válida para algum outro código específico ou se pudermos provar que conditionisso começará falso. Mas seu exemplo é equivalente no caso geral a:

if ( array.length > 0 ) {
  // Some other code.
}
for ( int i = 1; i < array.length && !condition; i++ ) {
  // Some other code.
}

Se algum outro código não for de uma linha, você poderá movê-lo para uma função para não se repetir e quase refatorar seu loop em uma função recursiva de cauda.

Eu reconheço que esse não foi o ponto principal da sua pergunta e você estava mantendo a simplicidade.


O problema não é que o intervalo dificulte a discussão sobre o código, mas o problema é que o intervalo em locais aleatórios torna o código complicado. Se isso é realmente necessário, não é difícil argumentar por causa da quebra, mas porque o código precisa fazer coisas complicadas.
gnasher729

Aqui está por que eu discordo: se você sabe que não há nenhuma breakdeclaração, então você sabe qual é a condição do loop e que o loop pára quando essa condição é falsa. Se houver um break? Depois, existem várias maneiras pelas quais o loop pode terminar e, no caso geral, descobrir quando um deles pode interromper o loop está literalmente resolvendo o Problema da Parada. Na prática, minha maior preocupação é que o loop pareça fazer uma coisa, mas, na verdade, quem quer que tenha escrito o código após o loop ignorou um caso extremo escondido em sua lógica complexa. É difícil perder coisas na condição de loop.
Davislor 28/02/19

0

Sim, mas sua sintaxe não é convencional e, portanto, é ruim (tm)

Espero que seu idioma suporte algo como

while(condition) //condition being a condition which if true you want to continue looping
{
    do thing; //your conditionally executed code goes here
    i++; //you can use a counter if you want to reference array items in order of index
}

2
talvez eu deveria ter usado uma palavra diferente para 'condição' Eu não quis dizer isso literalmente para significar a mesma condição exata no exemplo
Ewan

11
Não apenas o loop for nem remotamente não é convencional, como também não há razão para que um loop while desse formulário seja melhor do que um equivalente para loop. De fato, a maioria das pessoas diria que é pior, como os autores das Diretrizes Principais
Sean Burton

2
Algumas pessoas odeiam alternativas criativas. Ou olhando para um problema de uma maneira diferente da que está na cabeça deles. Ou, mais geralmente, asnos inteligentes. Eu sinto sua dor irmão!
Martin Maat

11
@sean desculpe cara, eu sei que as pessoas odeiam saber que estão erradas, mas eu te refiro a es.77
Ewan

2
Isso whileenfatiza o monstro no código - a exceção oculta no código rotineiro / mundano. A lógica de negócios é frontal e central, a mecânica de loop é subsumida. Evita a reação "espere um minuto ..." à foralternativa do loop. Esta resposta corrige o problema. absolutamente voto.
Radarbob 02/0318

0

Se você está preocupado com a fordificuldade de ler uma afirmação excessivamente complexa , essa é definitivamente uma preocupação válida. Perder espaço vertical também é um problema (embora menos crítico).

(Pessoalmente, não gosto da regra de que as ifdeclarações sempre devem ter chaves, o que é em grande parte a causa do espaço vertical desperdiçado aqui. Observe que o problema está desperdiçando espaço vertical. Usar o espaço vertical com linhas significativas não deve ser um problema.)

Uma opção é dividi-lo em várias linhas. Definitivamente, é isso que você deve fazer se estiver usando forinstruções realmente complexas , com várias variáveis ​​e condições. (Este é para mim um melhor uso do espaço vertical, dando ao máximo de linhas possível algo significativo.)

for (
   int i = 0, j = 0;
   i < array.length && !condition;
   i++, j++
) {
   // stuff
}

Uma abordagem melhor pode ser tentar usar uma forma mais declarativa e menos imperativa. Isso variará dependendo do idioma ou talvez você precise escrever suas próprias funções para ativar esse tipo de coisa. Também depende do que conditionrealmente é. Presumivelmente, ele deve ser capaz de mudar de alguma forma, dependendo do que está na matriz.

array
.takeWhile(condition)  // condition can be item => bool or (item, index) => bool
.forEach(doSomething); // doSomething can be item => void or (item, index) => void

Dividindo um complexo ou incomum fordeclaração em várias linhas é a melhor idéia em toda esta discussão
user949300

0

Uma coisa que foi esquecida: quando interrompo um loop (não faça todas as iterações possíveis, não importa como implementadas), geralmente é o caso de não apenas querer sair do loop, mas também quero saber por que isso aconteceu . Por exemplo, se eu procurar um item X, não apenas rompo o loop, também quero saber que X foi encontrado e onde está.

Nessa situação, ter uma condição fora do loop é bastante natural. Então eu começo com

bool found = false;
size_t foundIndex;

e no loop vou escrever

if (condition) {
    found = true;
    foundIndex = i;
    break;
}

com o loop for

for (i = 0; i < something && ! found; ++i)

Agora, verificar a condição no loop é bastante natural. A existência de uma instrução "break" depende da existência de processamento adicional no loop que você deseja evitar. Se algum processamento for necessário e outro não, você pode ter algo como

if (! found) { ... }

em algum lugar do seu loop.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.