私の質問は:
if (/* condition A */)
{
if(/* condition B */)
{
/* do action C */
}
else
/* ... */
}
else
{
/* do action C */
}
アクションCのコードを2回ではなく1回だけ書くことは可能ですか?
それを簡単にする方法は?
私の質問は:
if (/* condition A */)
{
if(/* condition B */)
{
/* do action C */
}
else
/* ... */
}
else
{
/* do action C */
}
アクションCのコードを2回ではなく1回だけ書くことは可能ですか?
それを簡単にする方法は?
回答:
この種の問題の最初のステップは、常に論理テーブルを作成することです。
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
}
このロジックは短いですが、将来のプログラマーが維持するのが難しい場合があることに注意してください。
B
に副作用がある場合、ロジックテーブルはそれを考慮する必要があります。
A && !B
ケースが何もしない場合は、!(A && !B)
と同等!A || B
です。これはif (!A || B) { /* do action C */ }
、空のブロックを実行して回避できることを意味します。
if (A && !B)
将来のプログラマが維持することが本当に難しい場合、彼らを助けることは本当にありません。
次の2つのオプションがあります。
「アクションC」を実行する関数を記述します。
ネストされたifステートメントがそれほど多くないように、ロジックを再配置します。「アクションC」が発生する原因となる状況を考えてみてください。「条件B」が真または「条件A」が偽の場合に発生するようです。これは「NOT A OR B」と書くことができます。これをCコードに変換すると、
if (!A || B) {
action C
} else {
...
}
これらの種類の表現についてさらに学ぶために、「ブール代数」、「述語論理」、および「述語計算」をグーグルすることをお勧めします。これらは、数学に関する深いトピックです。すべてを学ぶ必要はなく、基本を学ぶだけです。
「短絡評価」についても学ぶ必要があります。このため、元のロジックを正確に複製するには、式の順序が重要です。一方でB || !A
論理的に等価であるとき、条件としてこれを使用すると、「アクションC」を実行しますB
の値に関係なく真ですA
。
...
ています。それがまったく何もない場合(つまり、「これらの条件が満たされている場合はCを実行し、それ以外の場合は何もしない」)、else
ステートメントは完全に省略できるため、これは明らかに優れたソリューションです。
次のようにステートメントを簡略化できます。
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
}
if (!A || B)
B || !A
結果になりますtrue
B
true
A
A
をB
表しているかによって、大きな違いが生じる可能性があります。
パターンマッチングを使用する言語では、QuestionCの回答の真理値表をより直接的に反映する方法でソリューションを表現できます。
match (a,b) with
| (true,false) -> ...
| _ -> action c
構文に慣れていない場合、各パターンは|で表されます。(a、b)と一致する値が続き、アンダースコアは「その他の値」を意味するワイルドカードとして使用されます。アクションc以外の処理を実行する唯一のケースはaがtrueでbがfalseの場合であるため、これらの値を最初のパターン(true、false)として明示的に宣言し、その場合に実行する必要があることをすべて実行します。他のすべてのケースでは、「ワイルドカード」パターンに陥り、アクションcを実行します。
問題の説明:
条件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 */
}
inline
、Cとconstexpr
C ++にマークを付けますか?
ええと、これも私をつまずかせましたが、Code-Apprenticeによって指摘されているdo action C
ように、nested- else
blockを実行する必要があることが保証されているため、コードを次のように簡略化できます。
if (not condition A or condition B) {
do action C
} else {
...
}
これが次の3つのケースです。
do action C
あなたの質問のロジックでは、必要condition A
とcondition B
するtrue
-このロジックでは、我々は2に達している場合回目に用語をif
-statementそして、我々はそれが知ってcondition A
いるtrue
、我々はそれがある評価する必要があり、すべてのようcondition B
ですtrue
else
あなたの質問のロジックで-ブロックが必要condition A
であることをtrue
とcondition B
するfalse
-私たちは達することができる唯一の方法else
ならば、このロジックに-ブロックは次のようになりcondition A
ましたtrue
とcondition B
しましたfalse
else
質問のロジックの外側の-blockは必須condition A
であるfalse
-このロジックでcondition A
はfalseの場合もdo action C
ここで私を矯正するためのコード見習いへの小道具。編集せずに正しく提示したので、彼の回答を受け入れることをお勧めします:/
B
場合にのみ評価され!A
ます。したがって、else
ステートメントを実行するには、両方が失敗する必要があります。
!A || B
がなくても、!A
との両方B
が偽の場合は、正確に偽になります。したがって、実行A
時に真になりますelse
。再評価する必要はありませんA
。
ロジックの概念では、次のようにこの問題を解決できます。
f = ab +!a
f =?
実証済みの問題として、これはになりf = !a + b
ます。真理値表、カルノーマップなど、問題を証明するいくつかの方法があります。
したがって、Cベースの言語では、次のように使用できます。
if(!a || b)
{
// Do action C
}
PS:Karnaugh Mapは、より複雑な一連の条件にも使用されます。これは、ブール代数式を簡略化する方法です。
すでに良い答えはありますが、この方法は、ブール代数が初めてで真理値表を評価する人にとって、より直感的であると考えました。
あなたが最初にしたいことは、Cを実行したい条件の下での外観です。これはの場合(a & b)
です。また、時!a
。だからあなたは(a & b) | !a
ます。
最小化したい場合は続行できます。「通常の」算術の場合と同様に、乗算することができます。
(a & b) | !a = (a | !a) & (b | !a)
。a | !aは常にtrueなので、取り消し線を引くだけで済み、結果は最小化されます。b | !a
。順序に違いがある場合は、!aがtrueの場合にのみbをチェックする必要があるため(たとえば、!aがnullポインターチェックであり、bが、コメントで指摘されている@LordFarquaadのようなポインターの操作である場合)、 2つを切り替えたい。
他のケース(/ * ... * /)は、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.
}
このように、より多くのオペランドを使用して項を最小化することもできます。これにより、真理値表がすぐに醜くなります。もう1つの優れたアプローチは、Karnaughマップです。しかし、これについてはこれ以上詳しく説明しません。
コードをテキストのように見せるには、ブールフラグを使用します。ロジックが特に不明瞭な場合は、コメントを追加します。
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
{
...
}
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();
そして、2つのケースが同じ本体を持ち、組み合わせることができることがわかります。
if (!A || B) {
C();
return;
}
D();
改善するオプションのことは次のとおりです。
コンテキストに依存しますが、!A || B
混乱する場合は、1つ以上の変数に抽出して意図を説明します
いずれかC()
またはD()
非例外的なケースがそうならば、最後に行くべきでD()
、その後反転し、例外ではif
最後にもう一度