2

読みにくいために 2 つのスケジュール項目が重複しているかどうかを判断するテストを分けました。

論理ステートメントを単純化するのに役立つアプリケーションはありますか?

例: (元は間違った例ですが、私がこれを要求する理由を公開しています)

if (x < y && y < z && x < z)  

に減らすことができます

if (x < y && y < z)

私のコードは次のとおりです。

return (shift.Start <= shift2.Start && shift.End >= shift2.End) || (shift2.Start <= shift.Start && shift2.End >= shift.Start)

私はそれをもっと簡単にしたいと思っています.

これは実際には言語に依存しないため、可能性を見つけるために別のスクリプトに変換することもできます。たとえば、C# である必要はありません。

4

11 に答える 11

9

重複するロジックを殺せば、一石二鳥です。DRY を取得し、関数名 (金持ちのコメント) を取得します。

class Shift:
  def encompasses(other_shift)
    self.start <= other_shift.start && self.end >= other_shift.end

...

return shift1.encompasses(shift2) || shift2.encompasses(shift1)
于 2010-01-15T21:12:28.360 に答える
7

この種の変更には非常に注意してください。一見単純に見えるかもしれませんし、ブール論理 (および DeMorgan の法則) を理解するのはそれほど難しくありませんが、個々のケースを見ると、潜在的な落とし穴がしばしばあります。

例: if (x < y && y < z) は if (x < z) に簡略化できます

が依然として より大きい場合(x < z)、これは正しくありません。その状態では、元のテストに合格しません。yz

于 2010-01-15T20:34:29.790 に答える
4

(< は推移的) をx < y && y < z意味x < zしますが、その逆は成り立たないため、式は等価ではありません。実際、 が のようyに定義されている場合Integer y = null、前者は Java で NPE を引き起こしたり、SQL で UNKNOWN を引き起こしたりすることさえあります。

于 2010-01-15T20:34:35.697 に答える
3

複雑なロジックステートメントに関しては、通常、時期尚早の最適化(すべての悪の根源など)を試みるよりも、読み取り可能な方法でコードをフォーマットするのが最善です。

例えば:

return (shift.Start <= shift2.Start && shift.End >= shift2.End) || (shift2.Start <= shift.StartTime && shift2.End >= shift.Start)

読みやすさと保守性のために、次のようにリファクタリングできます。

bool bRetVal = false;
bRetVal = (    (   (shift.Start <= shift2.Start)
                && (shift.End >= shift2.End))
            || (   (shift2.Start <= shift.StartTime)
                && (shift2.End >= shift.Start)))
return bRetVal;

ほとんどの場所では、大きなロジックブロックに対して上記のようなものを定義するコーディング標準が維持されています。1行の怪物よりも、読んで理解できるコードを数行余分に維持したいと思います。

于 2010-01-15T20:47:18.057 に答える
3

論理ステートメントを単純化するのに役立つアプリケーションはありますか?

質問のこの部分に取り組んでいる人を誰も見ませんでした。

ブール論理を操作するためのテクニックがあります。大学時代 (BSEE) に戻って、カルノー マップを使用していました。基本的に、非常に複雑な任意の真理値表を使用して、正しく最適化された論理式を決定できます。ifこれを使用して、回路内の論理ゲートの数を減らしました。これは、複雑なステートメントを単純化することに似ています。

長所:

  • 非常に複雑で任意の真理値表を比較的簡単に実装/最適化できます。

短所:

  • 結果として得られるロジックは、通常、真理値表の意図とほとんど似ていません。他の人が示唆しているように、これは「判読不能」です。
  • 真理値表の 1 つのセルを変更すると、まったく異なる式になることがよくあります。単純な設計の微調整は書き直しになるため、保守できません。
  • 最適化されていないロジックは、設計コストは同じですが、以前よりもはるかに安価です。

最終的に最も重要なことは、真理値表/論理式の正確性です。エラーは、プログラムが正しく動作しないことを意味します。実装する必要があるロジックの定義を正しく理解していなければ、アプリケーションや設計手法は役に立ちません。

私の意見では、現実世界の問題で、この種の手法から本当に恩恵を受けるほど複雑なものはほとんどありませんが、実際には存在します。

于 2010-01-15T22:06:38.730 に答える
2

これを行うときは本当に注意する必要があります...たとえば、あなたが示した例は単に真実ではありません...

もし、、、x = 1そしてy = 2z = 2そしてx < y = true、そしてx < z = true、しかしy < z = false

このタイプの理由付けでは、これらの状況でコードを読みやすくする必要があり、取得できる最も効率的なコードについて心配する必要はありません。

于 2010-01-15T20:35:32.073 に答える
1

次のようなステートメントをラップできる場合があります。

shift.Start <= shift2.Start && shift.End >= shift2.End

次のようなブール関数に変換して読みやすくします。

function ShiftWithinValidRange //(terrible name here, but you get the idea)
{
    return (shift.Start <= shift2.Start && shift.End >= shift2.End);    
}
于 2010-01-15T20:44:19.140 に答える
1

StartとStartTimeが実際には同じフィールドであると想定すると、条件は次のようになります。

(a <= b && c >= d) || (b <= a && d >= c)

これをに変えることができます

(a <= b && d <= c) || (b <= a && c <= d)

しかし、これはまだそれほど単純化されていないように見えます。

于 2010-01-15T20:48:23.527 に答える
0

これは危険であるだけでなく、コードの保守が困難になることがよくあります。ブール論理は、特定のステップに分割すると理解しやすくなります。ロジックを凝縮すると、ロジックを理解しにくくなることがよくあります。

つまり、あなたの例では、x < z私たちが本当に知りたいのは、なぜかどうかをチェックするのx < y && y < zですか?

多くの場合、最も単純なソリューションが最適です。ロジックを「クーラー」に凝縮しますが、読みにくいコードは長期的には良くありません。

于 2010-01-15T20:42:12.997 に答える
0

ウェイン・コンラッドの答えは正しいと思いますが、娯楽目的のためだけに、別の言い方をします (私は思います):

(long) shift.Start.CompareTo(shift2.Start) * (long) shift.End.CompareTo(shift2.End) <= 0

これは実際に高速ですか?知らない。確かに読みにくいです。

于 2010-01-15T21:16:56.373 に答える
0

私はあなたのための一般的な解決策を持っていませんが、Lisp 構文を使用すると、私にはずっと簡単に見えます:

(and (< x y)
     (< y z)
     (< x z))

次に、最初の 2 つの句に注意してください。

(and (< x y)
     (< y z))

次のように組み合わせることができます。

(and (< x y z))

したがって、完全な式は次のようになります。

(and (< x y z)
     (< x z))

2 番目のものは冗長であることは明らかなので、次のようになります。

(and (< x y z))

または単に:

(< x y z)

C構文では次のとおりです。

(x < y && y < z)
于 2010-01-15T21:03:19.550 に答える