A koşulu eşleşirse, C eylemini gerçekleştirmek için B koşulunun eşleştirilmesi gerekir.


148

Sorum şu:

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

C eylem kodunu iki kez yerine bir kez yazmak mümkün müdür?

Nasıl basitleştirilir?


56
"C eylemi" kodunu bir fonksiyona koy?
CinCout

26
Bu gerçekten C ++ soru ile ilgili değil üzücü HNQ var: /
YSC

2
Bana yardım ettiğiniz için herkese teşekkürler! Başlangıçta, her şeyin yolunda olduğundan emin olmak istiyorum, bu yüzden iç içe geçmiş olsaydım. Çünkü tahmin ettiğim en basit yol bu. Bir dahaki sefere soru sorduktan sonra daha fazla çaba göstermeye çalışacağım. Herkesin iyi günler
dilerim

13
Bu çok iyi bir stratejidir: önce çalışan bir kod yazın, daha sonra daha sonra zarif ve verimli hale getirme konusunda endişelenin.
Code-Apprentice

3
@ Zaman cevap olarak gönderdim. Bir yan notta, orada daha az oy görmek üzücü.
CinCout

Yanıtlar:


400

Bu tür problemlerde ilk adımınız her zaman bir mantık tablosu yapmaktır.

A | B | Result
-------------------
T | T | do action C
T | F | ...
F | T | do action C
F | F | do action C

Masayı oluşturduktan sonra çözüm açıktır.

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

Bu mantığın daha kısa olsa da gelecekteki programcıların bakımı zor olabileceğini unutmayın.


35
OP'nin bunu nasıl geliştireceğini anlamasına yardımcı olmak için doğruluk tablosunu göstermenizi gerçekten seviyorum. Bunu bir adım daha ileri taşıyabilir ve boolean ifadesini doğruluk tablosundan nasıl elde ettiğinizi açıklayabilir misiniz? Programlamaya ve boole mantığına yeni giren biri için, bu muhtemelen hiç açık değildir.
Code-Apprentice

14
Değerlendirmenin Byan etkileri varsa mantık tablosu bunu hesaba katmalıdır.
Yakk - Adam Nevraumont

79
@Yakk Cevabım iki nedenden dolayı yan etkileri ele almıyor. İlk olarak, çözüm (tesadüfen) doğru yan etki davranışına sahiptir. İkincisi ve daha da önemlisi, yan etkilere sahip A ve B kötü kod olacaktır ve bu saçak vaka hakkında bir tartışma, temelde boole mantığı ile ilgili bir soru için dikkat dağıtıcı olacaktır.
QuestionC

52
Belki de kayda değer bir A && !Bdurumun olmaması durumunda: buna !(A && !B)eşdeğerdir, !A || Bbu da if (!A || B) { /* do action C */ }boş bir blok yapabileceğiniz ve kaçınabileceğiniz anlamına gelir .
KRyan

54
Eğer if (A && !B)gelecek programcılar korumak için gerçekten zor, o zaman gerçekten hiç onlara yardımcı yoktur.
Ray

65

İki seçeneğiniz var:

  1. "C eylemini" gerçekleştiren bir fonksiyon yazın.

  2. Mantığınızı, çok fazla iç içe if ifadesi olmayacak şekilde yeniden düzenleyin. Kendinize hangi koşulların "C eylemine" neden olduğunu sorun. Bana "B koşulu" ya da "A koşulu" yanlış olduğunda olduğu gibi geliyor. Bunu "A OR B DEĞİL" olarak yazabiliriz. Bunu C koduna çevirerek,

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

Bu tür ifadeler hakkında daha fazla bilgi edinmek için, "boole cebiri", "yüklem mantığı" ve "yüklem hesabı" nı aramanızı öneririm. Bunlar derin matematiksel konular. Her şeyi öğrenmenize gerek yok, sadece temel bilgiler.

Ayrıca "kısa devre değerlendirmesi" hakkında bilgi edinmelisiniz. Bu nedenle, orijinal mantığınızı tam olarak çoğaltmak için ifadelerin sırası önemlidir. B || !AMantıksal olarak eşdeğer olsa da, bunu koşul olarak kullanmak B, değeri ne olursa olsun, doğru olduğunda "C eylemini" yürütür A.


15
@Yakk Bkz. DeMorgan Yasaları.
Code-Apprentice

@ Kod-Çırak Lütfen kötü mantıklı düşüncemi affet. (! A || B) ve (A &&! B) arasında herhangi bir fark olup olmadığını sormak istiyorum. Her ikisi de benim sorunum için iyi görünüyor. Sizin ve QuestionC'nin yaklaşımı demek istiyorum.
starf15h

6
@ Starf15h Bir başka önemli fark daha var: "C eyleminin" gerçekleştirildiği yer. Bu fark, iki çözümümüzü tamamen eşdeğer kılmaktadır. Burada neler olduğunu anlamanıza yardımcı olması için Google "deMorgan Yasalarını" kullanmanızı öneririm.
Code-Apprentice

5
İki çözüm tam olarak eşittir, fakat pratik bir fark olabileceğini tam olarak ne bağlı ...olduğunu . Hiç bir şey değilse (yani, “bu koşullar karşılanırsa C yapın; aksi takdirde hiçbir şey yapmayın”), o zaman bu açıkça üstün bir çözümdür, çünkü elseifade tamamen dışarıda bırakılabilir.
Janus Bahs Jacquet

1
Ayrıca, A ve B'nin adlarına bağlı olarak, bu düzenleme bir insan için QuestionC düzenlemesinden daha okunabilir veya daha az okunabilir olabilir .
Michael - Clay Shirky

15

İfadeyi şu şekilde basitleştirebilirsiniz:

if ((A && B) || (!A)) // or simplified to (!A || B) as suggested in comments
{
    do C
}

Aksi takdirde 'C' kodunu ayrı bir fonksiyona koyun ve arayın:

DoActionC()
{
    ....
    // code for Action C
}
if (condition A)
{
    if(condition B)
      {
         DoActionC(); // call the function
      }
    else
      ...
}
else
{
   DoActionC(); // call the function
}

7
Veya daha basitif (!A || B)
Tas

2
Mantıken, ((A && B) ||! A), (B ||! A) ile eşdeğerdir
Code-Apprentice

@ Code-Apprentice B || !A, kısa devre nedeniyle gerçekten kontrol etmeden, trueancak Bşu şekilde sonuçlanırtrueA
CinCout

1
@CinCout İyi bir nokta. İfadem teorik bir boole mantığı açısından hala doğru olsa da, kısa devre boole operatörlerinin pratiklerini dikkate almadım. Neyse ki, kendi cevabım doğru sıraya sahip.
Code-Apprentice

1
Bu yüzden mantık açısından, düzen önemli değil. Bununla birlikte, bakım ve okunabilirlik açısından, tam olarak neyin Ave neyin temsil edildiğine bağlı olarak büyük bir fark olabilir B.
Code-Apprentice

14

Kalıp eşleşmesi olan bir dilde, çözümü QuestionC'nin cevabındaki doğruluk tablosunu daha doğrudan yansıtacak şekilde ifade edebilirsiniz.

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

Sözdizimine aşina değilseniz, her bir desen bir | ardından (a, b) ile eşleşecek değerler gelir ve alt çizgi "diğer değerler" anlamına gelmek için joker karakter olarak kullanılır. C eyleminden başka bir şey yapmak istediğimiz tek durum a'nın doğru ve b'nin yanlış olduğu durum olduğundan, bu değerleri açıkça ilk kalıp (doğru, yanlış) olarak belirtiriz ve sonra bu durumda yapılması gerekeni yaparız. Diğer tüm durumlarda, "joker karakter" desenine geçiyoruz ve eylem yapıyoruz c.


10

Sorun bildirimi:

A koşulu eşleşirse, C eylemini gerçekleştirmek için B koşulunun eşleştirilmesi gerekir.

tarif ima : bir ima B , bir mantık teklif eşdeğer !A || B(diğer yanıtlar belirtildiği gibi) hazırlanmıştır:

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

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

Belki de inlineC ve constexprC ++ için işaretleyin ?
einpoklum

@einpoklum Bu ayrıntıların bazılarına girmedim çünkü bu soru gerçekten bir dil belirtmedi (ancak C benzeri sözdizimiyle bir örnek verdi), bu yüzden C benzeri sözdizimiyle bir cevap verdim. Şahsen bir makro kullanırım ki B koşulu gereksiz değerlendirilmez.
jamesdlin

6

Ugh, bu da beni harekete geçirdi, ancak Code-Apprentice tarafından işaret edildiği gibi do action C, iç içe elsebloğu kullanmamız ya da çalıştırmamız gerekiyor , böylece kod basitleştirilebilir:

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

3 vakayı şu şekilde vuruyoruz:

  1. İç içe do action Csizin Sorunun mantık gerekli condition Ave condition Bolması true- bu mantık, biz 2 ulaşırsa nd terimini if-Bildirim sonra bunu biliyoruz condition Aolduğu trueo zamanın değerlendirmek için gereken tüm böylelikle condition Bolduğunutrue
  2. İç içe elsesizin Sorunun mantık -blok- gerekli condition Aolduğu trueve condition Bolmaya false- biz ulaşmasının tek yolu elseise olacaktı bu mantık -Blok condition Avardı trueve condition Bvardıfalse
  3. elseSorunuzun mantığındaki dış bloğun condition Aolması gerekiyor false- Bu mantıkta condition Ayanlışsa biz dedo action C

Beni buradan düzelttiği için Code-Apprentice'den aksesuarlar. Cevabını kabul etmenizi öneririm , çünkü düzenlemeden doğru bir şekilde sundu: /


2
"Koşul A" nın tekrar değerlendirilmesi gerekmediğine dikkat edin. C ++ 'da, hariç tutulan ortadaki yasaya sahibiz. "Koşul A değil" yanlışsa, "koşul A" mutlaka doğrudur.
Code-Apprentice

1
Kısa devre değerlendirmesi nedeniyle, Bsadece !Ayanlışsa değerlendirilecektir . Bu nedenle, elseifadeleri yürütmek için her ikisi de başarısız olmalıdır .
Code-Apprentice

Kısa devre değerlendirmesi olmasa bile !A || Bher ikisi de tam olarak yanlış !Ave Byanlıştır. Bu nedenle, yürütüldüğünde Adoğru olacaktır else. Yeniden değerlendirmeye gerek yok A.
Code-Apprentice

@ Kod-Çırak Kokuşmuş, mükemmel gözlem, cevabımı düzelttim, ama seninkinin kabul edilmesini önerdim. Sadece ortaya koyduğun şeyi açıklamaya çalışıyorum.
Jonathan Mee

Keşke her vakayı açıkladığınız için size bir oy daha verebilirim.
Code-Apprentice

6

Mantık kavramında, bu sorunu aşağıdaki gibi çözebilirsiniz:

f = ab +! a
f =?

Kanıtlanmış bir sorun olarak, bu sonuçlanır f = !a + b. Sorunu doğruluk tablosu, Karnaugh Haritası ve benzeri gibi kanıtlamanın bazı yolları vardır .

Yani C tabanlı dillerde aşağıdaki gibi kullanabilirsiniz:

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

Not: Karnaugh Haritası aynı zamanda daha karmaşık koşullar için de kullanılır. Boole cebri ifadelerini basitleştirmenin bir yöntemidir.


6

Zaten iyi cevaplar olmasına rağmen, bu yaklaşımın Boolean cebirinde yeni olan birine, daha sonra bir doğruluk tablosunu değerlendirmek için daha sezgisel olabileceğini düşündüm.

Yapmak istediğiniz ilk şey, hangi koşullar altında C yürütmek istediğinize bakmaktır (a & b). Ayrıca ne zaman !a. Yani var (a & b) | !a.

Eğer simge durumuna küçültmek isterseniz devam edebilirsiniz. Tıpkı "normal" aritmetiklerde olduğu gibi, çarpabilirsiniz.

(a & b) | !a = (a | !a) & (b | !a). a | ! Bir her zaman doğru, yani sadece minimize sonuçla hangi yaprakları, bunu geçebilir: b | !a. Siparişin bir fark yaratması durumunda, sadece b! ikisini değiştirmek istiyorum.

Diğer durum (/ * ... * /), c yürütülmediğinde her zaman yürütülür, böylece başka bir duruma koyabiliriz.

Ayrıca, c eylemini bir yönteme koymanın her iki şekilde de mantıklı olduğu söylenebilir.

Bizi aşağıdaki kodla bırakır:

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

Bu şekilde, doğruluk tablolarıyla hızla çirkin hale gelen daha fazla işlenenle terimleri en aza indirebilirsiniz. Bir başka iyi yaklaşım da Karnaugh haritaları. Ama şimdi bunun içine girmeyeceğim.


4

Kodun metne daha fazla benzemesini sağlamak için boole bayraklarını kullanın. Mantık özellikle belirsizse, yorum ekleyin.

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

Bir yönteme C ayıklamak ve daha sonra her durumda işlevden en kısa sürede çıkmak. elsesonunda tek bir şey içeren maddeler mümkünse neredeyse her zaman ters çevrilmelidir. İşte adım adım örnek:

Özü C:

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

İlk önce ifkurtulmak için önce ters çevir else:

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

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

İkinciden kurtulun else:

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

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

D();

Ve sonra iki vakanın aynı gövdeye sahip olduğunu ve birleştirilebileceğini fark edebilirsiniz:

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

D();

Geliştirilmesi gereken isteğe bağlı şeyler:

  • bağlama bağlıdır, ancak !A || Bkafa karıştırıcıysa amacı açıklamak için bir veya daha fazla değişkene çıkarın

  • hangisi C()veya D()olmayan istisnai durum eğer öyleyse, son gitmeli olan D()istisna sonra invert olduğu ifson bir kez


2

Bayrakları kullanmak da bu sorunu çözebilir

int flag = 1; 
if ( condition A ) {
    flag = 2;
    if( condition B ) {
        flag = 3;
    }
}
if(flag != 2) { 
    do action C 
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.