조건 A가 일치하면 조치 C를 수행하기 위해 조건 B를 일치시켜야합니다.
내 질문은 :
if (/* condition A */)
{
if(/* condition B */)
{
/* do action C */
}
else
/* ... */
}
else
{
/* do action C */
}
행동 코드 C를 두 번이 아니라 한 번만 쓰는 것이 가능합니까?
그것을 단순화하는 방법?
이러한 종류의 문제에서 첫 번째 단계는 항상 논리 테이블을 만드는 것입니다.
A | B | Result
-------------------
T | T | do action C
T | F | ...
F | T | do action C
F | F | do action C
일단 테이블을 만들면 해결책이 분명합니다.
if (A && !B) {
...
}
else {
do action C
}
이 논리는 더 짧지 만 미래 프로그래머가 유지하기 어려울 수 있습니다.
두 가지 옵션이 있습니다.
"액션 C"를 수행하는 함수를 작성하십시오.
중첩 된 if 문이 너무 많지 않도록 논리를 다시 정렬하십시오. "액션 C"가 발생하는 조건을 스스로에게 물어보십시오. "조건 B"가 참이거나 "조건 A"가 거짓 일 때 발생하는 것처럼 보입니다. 이것을 "NOT A OR B"로 쓸 수 있습니다. 이것을 C 코드로 변환하면
if (!A || B) { action C } else { ... }
이러한 종류의 표현에 대해 자세히 알아 보려면 인터넷 검색 "부울 대수", "조건 자 논리"및 "조건 자 미적분학"을 제안합니다. 이것들은 깊은 수학적 주제입니다. 모든 것을 배울 필요는 없으며 기본 사항 만 있습니다.
"단락 평가"에 대해서도 배워야합니다. 이 때문에 표현식의 순서는 원래 논리를 정확하게 복제하는 데 중요합니다. B || !A
논리적으로 동일 하지만 이 값을 조건으로 사용 B
하면 값에 관계없이 true 일 때 "action C"가 실행됩니다 A
.
다음과 같이 문장을 단순화 할 수 있습니다.
if ((A && B) || (!A)) // or simplified to (!A || B) as suggested in comments
{
do C
}
그렇지 않으면 'C'에 대한 코드를 별도의 함수에 넣고 호출하십시오.
DoActionC()
{
....
// code for Action C
}
if (condition A)
{
if(condition B)
{
DoActionC(); // call the function
}
else
...
}
else
{
DoActionC(); // call the function
}
패턴 일치가있는 언어에서는 QuestionC의 답변에 진리표를 더 직접 반영하는 방식으로 솔루션을 표현할 수 있습니다.
match (a,b) with
| (true,false) -> ...
| _ -> action c
If you're not familiar with the syntax, each pattern is represented by a | followed by the values to match with (a,b), and the underscore is used as a wildcard to mean "any other values". Since the only case where we want to do something other than action c is when a is true and b is false, we explicitly state those values as the first pattern (true,false) and then do whatever should be done in that case. In all other cases, we fall through to the "wildcard" pattern and do action c.
The problem statement:
If condition A is matched, condition B needs to be matched in order to do action C
describes implication: A implies B, a logical proposition equivalent to !A || B
(as mentioned in other answers):
bool implies(bool p, bool q) { return !p || q; }
if (implies(/* condition A */,
/* condition B */))
{
/* do action C */
}
Ugh, this tripped me up too, but as pointed out by Code-Apprentice we're guaranteed to need to do action C
or run the nested-else
block, thus the code could be simplified to:
if (not condition A or condition B) {
do action C
} else {
...
}
This is how we're hitting the 3 cases:
- The nested
do action C
in your question's logic requiredcondition A
andcondition B
to betrue
-- In this logic, if we reach the 2nd term in theif
-statement then we know thatcondition A
istrue
thus all we need to evaluate is thatcondition B
istrue
- The nested
else
-block in your question's logic requiredcondition A
to betrue
andcondition B
to befalse
-- The only way that we can reach theelse
-block in this logic would be ifcondition A
weretrue
andcondition B
werefalse
- The outer
else
-block in your question's logic requiredcondition A
to befalse
-- In this logic ifcondition A
is false we alsodo action C
Props to Code-Apprentice for straightening me out here. I'd suggest accepting his answer, since he presented it correctly without editing :/
In the logic concept, you can solve this problem as follow:
f = a.b + !a
f = ?
As a proven problem, this results in f = !a + b
. There are a some ways to prove the problem such as truth table, Karnaugh Map and so on.
So in C based languages you can use as follow:
if(!a || b)
{
// Do action C
}
P.S.: Karnaugh Map is also used for more complicate series of conditions. It's a method of simplifying Boolean algebra expressions.
Even though there are already good answers, I thought that this approach might be even more intuitive to someone who is new to Boolean algebra then to evaluate a truth table.
First thing you want to do is look, under which conditions you want to execute C. This is the case when (a & b)
. Also when !a
. So you have (a & b) | !a
.
If you want to minimize you can go on. Just like in "normal" arithmetic's, you can multiply out.
(a & b) | !a = (a | !a) & (b | !a)
. a | !a is always true, so you can just cross it out, which leaves you with the minimized result: b | !a
. In case the order makes a difference, because you want to check b only if !a is true (for example when !a is a nullpointer check and b is an operation on the pointer like @LordFarquaad pointed out in his comment), you might want to switch the two.
The other case (/* ... */) is will be always executed when c is not executed, so we can just put it in the else case.
Also worth mentioning is that it probably makes sense either way to put action c into a method.
Which leaves us with the following code:
if (!A || B)
{
doActionC() // execute method which does action C
}
else
{
/* ... */ // what ever happens here, you might want to put it into a method, too.
}
This way you can also minimize terms with more operands, which quickly gets ugly with truth tables. Another good approach are Karnaugh maps. But I won't go deeper into this now.
To make the code look more like text, use boolean flags. If the logic is especially obscure, add comments.
bool do_action_C;
// Determine whether we need to do action C or just do the "..." action
// If condition A is matched, condition B needs to be matched in order to do action C
if (/* condition A */)
{
if(/* condition B */)
do_action_C = true; // have to do action C because blah
else
do_action_C = false; // no need to do action C because blarg
}
else
{
do_action_C = true; // A is false, so obviously have to do action C
}
if (do_action_C)
{
DoActionC(); // call the function
}
else
{
...
}
if((A && B ) || !A)
{
//do C
}
else if(!B)
{
//...
}
I would extract C to a method, and then exit the function as soon as possible in all cases. else
clauses with a single thing at the end should almost always be inverted if possible. Here's a step by step example:
Extract C:
if (A) {
if (B)
C();
else
D();
} else
C();
Invert first if
to get rid of first else
:
if (!A) {
C();
return;
}
if (B)
C();
else
D();
Get rid of second else
:
if (!A) {
C();
return;
}
if (B) {
C();
return;
}
D();
And then you can notice that the two cases have the same body and can be combined:
if (!A || B) {
C();
return;
}
D();
Optional things to improve would be:
depends on context, but if
!A || B
is confusing, extract it to one or more variables to explain the intentwhichever of
C()
orD()
is the non-exceptional case should go last, so ifD()
is the exception, then invert theif
one last time
Using flags can also solve this problem
int flag = 1;
if ( condition A ) {
flag = 2;
if( condition B ) {
flag = 3;
}
}
if(flag != 2) {
do action C
}
'Programing' 카테고리의 다른 글
appCompat 22.1 이상에서 새로운 AlertDialog를 사용하고 스타일을 지정하는 방법 (0) | 2020.06.13 |
---|---|
커서를 잡기위한 CSS (드래그 앤 드롭) (0) | 2020.06.13 |
슬러그 (URL 문자열)를 만드는 PHP 함수 (0) | 2020.06.13 |
'구문 분석'의 반대말은 무엇입니까? (0) | 2020.06.13 |
Java의 @UniqueConstraint 주석 (0) | 2020.06.13 |