조건 A가 일치하면 조치 C를 수행하기 위해 조건 B를 일치시켜야합니다.


148

내 질문은 :

if (/* condition A */)
{
    if(/* condition B */)
      {
         /* do action C */
      }
    else
      /* ... */
}
else
{
   /* do action C */
}

행동 코드 C를 두 번이 아니라 한 번만 쓰는 것이 가능합니까?

그것을 단순화하는 방법?


56
"액션 C"에 대한 코드를 함수에 넣습니까?
CinCout

26
이것은 실제로 C ++ 질문 과 관련없는 것은 슬프다. HNQ에 도착 : /
YSC

2
도와 주셔서 감사합니다! 처음에는 모든 것이 제대로되어 있는지 확인하고 중첩 된 if를 사용하고 싶습니다. 이것은 내가 추측 한 가장 간단한 방법이기 때문입니다. 다음에 질문을 한 후에 더 많은 노력을 기울일 것입니다. 모두 좋은 하루
되세요

13
매우 효과적인 전략입니다. 먼저 작동하는 코드를 작성한 다음 나중에 우아하고 효율적으로 만드는 것에 대해 걱정하십시오.
코드 견습생

3
@Tim 나는 그것을 답변으로 게시했습니다. 참고로 더 적은 표를 보는 것은 슬픈 일입니다.
CinCout

답변:


400

이러한 종류의 문제에서 첫 번째 단계는 항상 논리 테이블을 만드는 것입니다.

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
}

이 논리는 더 짧지 만 미래 프로그래머가 유지하기 어려울 수 있습니다.


35
OP가 직접 개발하는 방법을 이해하는 데 도움이되는 진리표를 보여 주신 것이 정말 좋습니다. 한 걸음 더 나아가 진실 테이블에서 부울 표현을 얻는 방법을 설명 할 수 있습니까? 프로그래밍과 부울 로직을 처음 접하는 사람에게는 이것이 분명하지 않을 것입니다.
코드 견습생

14
평가 B에 부작용이있는 경우 논리 테이블이이를 설명해야합니다.
Yakk-Adam Nevraumont

79
@ Yakk 내 대답은 두 가지 이유로 부작용을 다루지 않습니다. 첫째, 솔루션은 (부수적으로) 올바른 부작용 동작을 갖습니다. 둘째, 더 중요한 것은 부작용이있는 A와 B는 나쁜 코드가 될 수 있으며 이러한 문제에 대한 논의는 근본적으로 부울 논리에 대한 질문을 산만하게 할 것입니다.
QuestionC

52
지적 아마도 가치, 경우에 A && !B케이스는 어떤 조합입니다 : !(A && !B)에 해당 !A || B당신이 할 수있는 것을 의미 if (!A || B) { /* do action C */ }하고, 빈 블록을 피하십시오.
KRyan

54
if (A && !B)미래의 프로그래머가 유지하기가 정말 어려운 경우 에는 도움이되지 않습니다.
Ray

65

두 가지 옵션이 있습니다.

  1. "액션 C"를 수행하는 함수를 작성하십시오.

  2. 중첩 된 if 문이 너무 많지 않도록 논리를 다시 정렬하십시오. "액션 C"가 발생하는 조건을 스스로에게 물어보십시오. "조건 B"가 참이거나 "조건 A"가 거짓 일 때 발생하는 것처럼 보입니다. 이것을 "NOT A OR B"로 쓸 수 있습니다. 이것을 C 코드로 변환하면

    if (!A || B) {
        action C
    } else {
        ...
    }
    

이러한 종류의 표현에 대해 자세히 알아 보려면 인터넷 검색 "부울 대수", "조건 자 논리"및 "조건 자 미적분학"을 제안합니다. 이것들은 깊은 수학적 주제입니다. 모든 것을 배울 필요는 없으며 기본 사항 만 있습니다.

"단락 평가"에 대해서도 배워야합니다. 이 때문에 표현식의 순서는 원래 논리를 정확하게 복제하는 데 중요합니다. B || !A논리적으로 동일 하지만 이 값을 조건으로 사용 B하면 값에 관계없이 true 일 때 "action C"가 실행됩니다 A.


15
@Yakk deMorgan의 법칙을 참조하십시오.
코드 견습생

@ Code-Apprentice 나의 나쁜 논리적 사고를 용서해주세요. (! A || B)와 (A &&! B) 사이에 차이가 있는지 묻고 싶습니다. 내 문제는 괜찮습니다. 나는 당신과 QuestionC의 접근 방식을 의미합니다.
starf15h

6
@ Starf15h "액션 C"가 실행되는 다른 중요한 차이점이 있습니다. 이 차이로 인해 두 솔루션이 정확히 동일합니다. 여기에 무슨 일이 일어나고 있는지 이해하는 데 도움이되는 Google "deMorgan 's Laws"를 추천합니다.
코드 견습생

5
두 솔루션은 정확히 동일하지만, 실제적인 차이가있을 수 있습니다 정확히 무엇에 따라 ...입니다 . 전혀 아무것도 없다면 (즉,“이러한 조건이 충족되면 C를 수행하고, 그렇지 않으면 아무것도하지 마십시오”), else진술은 단순히 완전히 생략 될 수 있기 때문에 이것은 분명히 우수한 솔루션 입니다.
Janus Bahs Jacquet

1
또한, A 및 B의 명칭에 따라,이 구성 은 QuestionC의 구성보다 인간에게 더 판독 가능하거나 덜 판독 가능할 수있다 .
마이클-클레이는 어 r 지

15

다음과 같이 설명을 단순화 할 수 있습니다.

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
}

7
또는 더 간단하게if (!A || B)
Tas

2
논리적으로, ((A && B) ||! A)는 (B ||! A)와 같습니다
Code-Apprentice

@ Code-Apprentice B || !A는 단락으로 인해 실제로 확인하지 않고 is 인 true경우에만 발생합니다BtrueA
CinCout

1
@CinCout 좋은 지적입니다. 이론적 부울 논리 관점에서 내 진술은 여전히 ​​옳지 만 단락 부울 연산자의 실용성을 고려하지 않았습니다. 다행히도 내 대답은 올바른 순서로되어 있습니다.
코드 견습생

1
따라서 논리적 인 관점에서 순서는 중요하지 않습니다. 그러나보기의 유지 보수 및 가독성 점에서, 정확히 무엇에 따라 큰 차이가있을 수 있습니다 AB위해 서있다.
코드 견습생

14

패턴 일치가있는 언어에서는 QuestionC의 답변에 진리표를 더 직접 반영하는 방식으로 솔루션을 표현할 수 있습니다.

match (a,b) with
| (true,false) -> ...
| _ -> action c

구문에 익숙하지 않은 경우 각 패턴은 | 뒤에 (a, b)와 일치하는 값이 오며 밑줄은 "다른 값"을 의미하는 와일드 카드로 사용됩니다. 액션 c 이외의 다른 작업을 수행하려는 유일한 경우는 a가 true이고 b가 false 인 경우에만 해당 값을 첫 번째 패턴 (true, false)으로 명시한 다음이 경우 수행해야 할 모든 작업을 수행합니다. 다른 모든 경우에는 "와일드 카드"패턴으로 넘어 가서 조치 c를 수행합니다.


10

문제 진술 :

조건 A가 일치하면 조치 C를 수행하기 위해 조건 B를 일치시켜야합니다.

시사점 설명 : A 는 (다른 답변에서 언급했듯이) 논리적 제안 인 B를 의미합니다 !A || B.

bool implies(bool p, bool q) { return !p || q; }

if (implies(/* condition A */,
            /* condition B */))
{
    /* do action C */
}

아마도 inlineC로 표시하고 constexprC ++로 표시합니까?
einpoklum

@einpoklum 나는이 질문이 실제로 언어를 지정하지 않았기 때문에 (그러나 C와 같은 구문으로 예제를 제공했기 때문에) 이러한 세부 사항 중 일부에 들어 가지 않았으므로 C와 같은 구문으로 대답했습니다. 개인적으로 조건 B가 불필요하게 평가되지 않도록 매크로를 사용합니다.
jamesdlin

6

Ugh, 이것도 저를 트립 시켰지만 Code-Apprentice지적한 것처럼do action C 중첩 else블록 이 필요 하거나 실행 해야 하므로 코드를 다음과 같이 단순화 할 수 있습니다.

if (not condition A or condition B) {
    do action C
} else {
    ...
}

이것이 우리가 세 가지 경우를 타격하는 방법입니다.

  1. 중첩 된 do action C질문의 논리가 필요 condition A하고 condition Btrue-이 논리에서, 우리는이 도달 할 경우 에서 용어를 if-statement 우리가 아는 condition A것입니다 true우리가 즉 평가하기 위해 필요한 모든 따라서 condition B이다true
  2. 중첩 된 else질문의 논리 - 블록이 필요 condition Atrue하고 condition Bfalse- 우리가 도달 할 수있는 유일한 방법 else경우 것이이 논리 - 블록을 condition A했다 true하고 condition B있었다false
  3. 외부 else질문의 논리 - 블록이 필요 condition Afalse하는 경우이 논리에 - condition A우리는 또한 거짓do action C

나를 바로 잡기위한 코드 견습생을위한 제안. 그가 편집하지 않고 올바르게 제시했기 때문에 그의 대답을 수락하는 것이 좋습니다 .


2
"조건 A"는 다시 평가할 필요가 없습니다. C ++에서는 제외 된 중간의 법칙이 있습니다. "조건 A가 아님"이 거짓이면 "조건 A"가 반드시 참입니다.
코드 견습생

1
단락 평가로 인해 거짓 인 B경우에만 평가됩니다 !A. 따라서 else명령문 을 실행하려면 둘 다 실패해야합니다 .
코드 견습생

심지어 단락없이 평가는 !A || B정확히 모두 거짓 !AB거짓. 따라서 실행 A하면 true else입니다. 재평가 할 필요가 없습니다 A.
코드 견습생

@ Code-Apprentice 글쎄, 훌륭한 관찰, 나는 내 대답을 수정했지만 당신의 것이 받아 들여질 것을 제안했다. 나는 당신이 이미 내놓은 것을 설명하려고합니다.
Jonathan Mee

각 사건을 설명하기 위해 또 다른 투표권을 줄 수 있기를 바랍니다.
코드 견습생

6

논리 개념에서이 문제를 다음과 같이 해결할 수 있습니다.

f = ab +! a
f =?

입증 된 문제로 결과는 다음과 같습니다 f = !a + b. 진리표, Karnaugh지도 와 같은 문제를 증명하는 몇 가지 방법이 있습니다. .

따라서 C 기반 언어에서는 다음과 같이 사용할 수 있습니다.

if(!a || b)
{
   // Do action C
}

PS : Karnaugh Map 은보다 복잡한 일련의 조건에도 사용됩니다. 부울 대수 표현을 단순화하는 방법입니다.


6

이미 좋은 대답이 있지만,이 접근법은 부울 대수를 처음 접한 사람에게 진리표를 평가하는 데 훨씬 직관적이라고 생각했습니다.

가장 먼저 할 일은 C를 실행하려는 조건에서 찾는 것 (a & b)입니다. 또한 때 !a. 그래서 당신은 있습니다 (a & b) | !a.

최소화하고 싶다면 계속 진행할 수 있습니다. "정상적인"산술과 마찬가지로 곱할 수 있습니다.

(a & b) | !a = (a | !a) & (b | !a). | ! a는 항상 사실이므로 그냥 건너 뛸 수 있으므로 결과가 최소화됩니다.b | !a . 순서에 차이가있는 경우! a가 true 인 경우에만 b를 검사하려고하기 때문에 (예 :! a가 nullpointer 검사이고 b가 @LordFarquaad가 주석에서 지적한 것과 같은 포인터에 대한 조작 인 경우), 둘을 바꾸고 싶어요

다른 경우 (/ * ... * /)는 c가 실행되지 않을 때 항상 실행되므로 else 경우에만 넣을 수 있습니다.

언급 할 가치가있는 것은 액션 c를 메소드에 넣는 방법 중 어느 것이나 의미가 있다는 것입니다.

다음과 같은 코드가 남습니다.

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.
}

이 방법으로 더 많은 피연산자가 포함 된 항을 최소화 할 수 있으며, 이는 진리표를 사용하여 빠르게 추한 것입니다. 또 다른 좋은 방법은 Karnaugh지도입니다. 하지만 지금은 더 깊이 들어 가지 않을 것입니다.


4

코드를 텍스트처럼 보이게하려면 부울 플래그를 사용하십시오. 논리가 명확하지 않은 경우 주석을 추가하십시오.

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
  {
  ...
  }

3
if((A && B ) || !A)
{
  //do C
}
else if(!B)
{
  //...
}

2

메소드에 C를 추출한 다음 가능한 한 빨리 함수를 종료합니다. else끝에 하나의 것을 가진 절은 가능하면 거의 항상 반전되어야합니다. 단계별 예제는 다음과 같습니다.

추출 C :

if (A) {
   if (B)
      C();
   else
      D();
} else
   C();

먼저 if제거하려면 먼저 반전하십시오 else.

if (!A) {
   C();
   return;
}

if (B)
   C();
else
   D();

두 번째를 제거하십시오 else:

if (!A) {
   C();
   return;
}

if (B) {
   C();
   return;
} 

D();

그리고 두 케이스가 동일한 몸체를 가지고 결합 될 수 있음을 알 수 있습니다.

if (!A || B) {
   C();
   return;
}

D();

개선해야 할 사항은 다음과 같습니다.

  • 상황에 따라 다르지만 !A || B혼동되는 경우 하나 이상의 변수로 추출하여 의도를 설명하십시오.

  • 의 중 C()또는 D()비 예외적 인 경우 그렇게하는 경우는, 마지막으로 가야입니다 D()예외가 다음 반전이며, if마지막으로


2

플래그를 사용하면이 문제를 해결할 수 있습니다

int flag = 1; 
if ( condition A ) {
    flag = 2;
    if( condition B ) {
        flag = 3;
    }
}
if(flag != 2) { 
    do action C 
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.