Eu tenho algum código que tem uma sequência de if
s que funciona, mas me sinto confuso. Basicamente, quero escolher o maior de três números inteiros e definir um sinalizador de status para dizer qual foi escolhido. Meu código atual é assim:
a = countAs();
b = countBs();
c = countCs();
if (a > b && a > c)
status = MOSTLY_A;
else if (b > a && b > c)
status = MOSTLY_B;
else if (c > a && c > b)
status = MOSTLY_C;
else
status = DONT_KNOW;
Esse padrão ocorre algumas vezes e, com nomes de variáveis longos, fica um pouco difícil confirmar visualmente que cada um if
está correto. Sinto que pode haver uma maneira melhor e mais clara de fazer isso; alguém pode sugerir alguma coisa?
Existem algumas duplicatas em potencial, mas elas não estão alinhadas com essa pergunta.
Na duplicata sugerida: Abordagens para verificar várias condições? todas as soluções sugeridas parecem igualmente desajeitadas como o código original, portanto, elas não fornecem uma solução melhor.
E este post Maneiras elegantes de lidar com se (se houver) outra coisa lida apenas com níveis de aninhamento e assimetria, que não é o problema aqui.
fonte
Respostas:
Fatorar lógica, retornar cedo
Conforme sugerido nos comentários, seria suficiente simplesmente agrupar sua lógica em uma função e sair mais cedo da com
return
a fim de simplificar bastante as coisas. Além disso, você pode fatorar um pouco da funcionalidade, delegando testes a outra função. Mais concretamente:Isso é mais curto que minha tentativa anterior:
O texto acima é um pouco mais detalhado, mas é fácil de ler o IMHO e não recalcula as comparações várias vezes.
Confirmação visual
Na sua resposta, você diz:
... também, na sua pergunta, você diz:
Talvez eu não entenda o que você está tentando alcançar: deseja copiar e colar o padrão em todos os lugares que precisar? Com uma função como o descrito acima, você captura o padrão de uma vez, e você verificar uma vez por todas que todas as comparações usar
a
,b
ec
conforme necessário. Então, você não precisa mais se preocupar quando chamar a função. Claro, talvez na prática o seu problema seja um pouco mais complexo do que o que você descreveu: se assim for, adicione alguns detalhes, se possível.fonte
MOSTLY_A
ouMOSTLY_C
no casoa == c
ea > b
. Isso está consertado. Obrigado.TL: DR; Seu código já está correto e "limpo".
Vejo muitas pessoas questionando a resposta, mas todo mundo está sentindo falta da floresta entre as árvores. Vamos fazer a análise completa da ciência da computação e matemática para entender completamente esta questão.
Primeiro, observamos que temos 3 variáveis, cada uma com 3 estados: <, = ou>. O número total de permutações é 3 ^ 3 = 27 estados, aos quais atribuirei um número único, denotado P #, para cada estado. Esse número P # é um sistema de números fatoriais .
Enumerando todas as permutações que temos:
Por inspeção, vemos que temos:
Vamos escrever um programa (veja a nota de rodapé) para enumerar todas essas permutações com valores para A, B e C. Classificação estável por P #:
Caso você estivesse se perguntando como eu sabia quais estados P # eram impossíveis, agora você sabe. :-)
O número mínimo de comparações para determinar a ordem é:
Log2 (27) = Log (27) / Log (2) = ~ 4,75 = 5 comparações
isto é, o coredump deu o número mínimo correto de 5 comparações. Eu formataria seu código como:
Para o seu problema, não nos preocupamos em testar a igualdade, para que possamos omitir dois testes.
Não importa o quão limpo / ruim o código seja, se ele receber a resposta errada, é um bom sinal de que você está lidando com todos os casos corretamente!
Em seguida, quanto à simplicidade, as pessoas continuam tentando "melhorar" a resposta, onde pensam que melhorar significa "otimizar" o número de comparações, mas isso não é exatamente o que você está perguntando. Você confundiu todo mundo onde perguntou "Sinto que pode haver um melhor", mas não definiu o que "melhor" significa. Menos comparações? Menos código? Comparações ótimas?
Agora, como você está perguntando sobre a legibilidade do código (dada a correção), eu faria apenas uma alteração no seu código para facilitar a leitura: Alinhe o primeiro teste com os outros.
Pessoalmente, eu escreveria da seguinte maneira, mas isso pode ser pouco ortodoxo para seus padrões de codificação:
Nota de rodapé: Aqui está o código C ++ para gerar as permutações:
Edições: com base no feedback, moveu TL: DR para o topo, removeu a tabela não classificada, esclareceu 27, limpou o código, descreveu estados impossíveis.
fonte
O @msw disse para você usar uma matriz em vez de a, b, ce @Basile disse para refatorar a lógica "max" em uma função. A combinação dessas duas idéias leva a
forneça uma função que calcule o índice máximo de uma matriz arbitrária:
e chame assim
O número total de LOC parece ter aumentado em relação ao original, mas agora você tem a lógica principal em uma função reutilizável e, se puder reutilizar a função várias vezes, ela começa a valer a pena. Além disso, a
FindStrictMaxIndex
função não está mais entrelaçada com seus "requisitos de negócios" (separação de interesses); portanto, o risco que você terá de modificá-lo mais tarde é muito menor do que na sua versão original (princípio aberto-fechado). Por exemplo, essa função não precisará ser alterada, mesmo que o número de argumentos seja alterado ou precise usar outros valores de retorno além de MOSTLY_ABC, ou você esteja processando outras variáveis além de a, b, c. Além disso, o uso de uma matriz em vez de 3 valores diferentes a, b, c também pode simplificar seu código em outros lugares.Obviamente, se em todo o programa houver apenas um ou dois locais para chamar essa função e você não tiver mais aplicativos para armazenar os valores em uma matriz, provavelmente eu deixaria o código original como está (ou use @ melhoria do coredump).
fonte
FindStrictMaxIndex()
podem não estar muito limpas, mas do ponto de vista do interlocutor, é razoavelmente óbvio o que está tentando ser alcançado.int
função digitada simples . Mas concordo com o seu comentário se alguém usar uma linguagem diferente como Python ou Perl.FindStrictMaxIndex
função pode ser reutilizada. Por uma ou apenas duas vezes de reutilização, isso não será recompensado, é claro, mas foi o que eu escrevi na minha resposta. Observe também as outras vantagens que mencionei acima em relação a mudanças futuras.return result[FindStrictMaxIndex(val,3)];
no ponto do código em que as 8 linhas originais foram colocadas . As outras partes, especialmenteFindStrictMaxIndex
ela própria, são completamente separadas da "lógica de negócios", que as tira do foco de alterar os requisitos de negócios.Você provavelmente deve usar uma macro ou uma função que
MAX
dê o máximo de dois números.Então você só quer:
Você pode ter definido
mas seja cauteloso (principalmente sobre efeitos colaterais) ao usar macros (pois
MAX(i++,j--)
se comportaria de maneira estranha)Então, melhor defina uma função
e use-o (ou pelo menos
#define MAX(X,Y) max2ints((X),(Y))
....)Se você precisar entender a origem do MAX, poderá ter uma macro longa como a
#define COMPUTE_MAX_WITH_CAUSE(Status,Result,X,Y,Z)
que é uma macro longado{
...}while(0)
Então você pode invocar
COMPUTE_MAX_WITH_CAUSE(status,res,a,b,c)
em vários lugares. É um pouco feio. I definido variáveis locaisx
,y
,z
para reduzir efeitos colaterais ruins ....fonte
Eu pensei mais sobre isso, então, como meu problema era principalmente a confirmação visual de que todas as comparações usavam as mesmas variáveis, acho que essa pode ser uma abordagem útil:
Que cada macro leva
a
,b
ec
na mesma ordem é fácil de confirmar, e o nome da macro salva-me ter que descobrir o que todas as comparações e ANDs estão fazendo.fonte