Üç booleandan en az ikisinin doğru olup olmadığını kontrol edin


579

Bir görüşmeci yakın zamanda bana şu soruyu sordu: a, b ve c olmak üzere üç boole değişkeni verildiğinde, üçünden en az ikisi doğruysa true değerini döndürür.

Benim çözümüm şöyle:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a && b) || (b && c) || (a && c)) {
        return true;
    }
    else{
        return false;
    }
}

Bunun daha da geliştirilebileceğini söyledi, ama nasıl?


170
Dönüş ifadesini satır içinde.
Finglas

45
Kulağa "IQ'yu en yüksek yapan kişi" gibi geliyor. Başarısız olurdum.
Chris Dutrow

79
atLeastTwo(iWantYou, iNeedYou, imEverGonnaLoveYou)
Andrew Grimm

92
İnsanlar neden en önemsiz soruları onaylıyor?
BlueRaja - Dany Pflughoeft

46
Genel ve anlaşılması kolay sorular çok oy alır. Çok spesifik ve teknik sorular sormaz.
Jay

Yanıtlar:


820

Yazmak yerine:

if (someExpression) {
    return true;
} else {
    return false;
}

Yazmak:

return someExpression;

İfadenin kendisine gelince, böyle bir şey:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return a ? (b || c) : (b && c);
}

veya bu (hangisini daha kolay kavrarsanız):

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return a && (b || c) || (b && c);
}

Bu test eder ave btam olarak bir kez ve cen çok kerede.

Referanslar


144
+1: bulmacanın güzel çözümü, ancak umarım gerçek dünyada böyle bir şey görmüyoruz :)
Juliet

124
@Juliet: Bilmiyorum, eğer bu gerçek dünya gereksinimi olsaydı (gerçek değişken isimleriyle) oldukça iyi okuyacağını düşünüyorum. Düşünün return hasGoodAttendance ? (passedCoursework || passed Exam) : (passedCoursework && passedExam), bana iyi geliyor.
Andrzej Doyle

18
Bunun kötü göründüğünü düşünmüyorum , ancak alandaki gereksinimin "en az iki" olduğu anlaşılırsa, okumanın daha kolay olacağını düşünüyorum atLeastTwo(hasgoodAttendance, passedCoursework, passedExam). "En az 2 bools doğru" fikri, kendi işlevini hak edecek kadar geneldir.
Ken

17
@Lese: Yüz yüze görüşmelerde en mikro optimize edilmiş kodu sormak pratik değildir ve söylemeye yararım. Mikro-optimizasyonlar, ihtiyaçtan kaynaklandığında, insan içgüdülerine (korkunç olduğu bilinen) değil, çalışma zamanı profil oluşturma sonuçları tarafından yönlendirilir. Kesinlikle görüşmecilere bunu daha da optimize etme sürecini sorabilirsiniz; bu sonucun kendisinden daha önemlidir.
poligenelubricants

17
Üçlü operatör, okuyabilmeniz gereken yaygın bir deyimdir. Eğer okuyamıyorsanız, okuyana kadar çalışmalısınız. Üçlü operatörün kullanımı aşağılayıcı anlamda "akıllı" olarak gördüğüm bir şey değildir. Ama evet, bunu "en az iki" mantığını sık sık kullanıyorsanız, bir yöntem çağrısının gövdesi olarak koyardım.
Stephen P

493

XOR'u nispeten basit bir soruna cevap vermek için kullanmak için ...

return a ^ b ? c : a

159
Vay, serin bir çözüm. Ama benim için ters çevrilmiş versiyonunu anlamak daha kolay: a == b? a: c
Rotsor

5
a ^ b? c: a ^ b? c: a ^ b? c: a
alexanderpas

4
Yay, .. XOR böyle kötü bir basına kavuşuyor ve nadiren kullanma şansına sahip oluyorsunuz.
EightyOne Unite

18
@ Stimul8d belki, booleans için! = İle aynıdır, ancak daha az okunabilir? Bunu benim için bir eureka anıydı ...
Tikhon Jelvis

2
Tamamen ikili formu tercih ederim: return ((a ^ b) & c) | (a & b). Dalsız (daha hızlı) ve okunması kolay: (a veya b doğrudur ve c doğrudur) veya (a ve b ikisi de doğrudur). (A | b) ve (a ^ b) öğelerinin bu formülle çalıştığını unutmayın.
flanglet

217

Neden tam anlamıyla uygulamıyorsunuz? :)

(a?1:0)+(b?1:0)+(c?1:0) >= 2

C dilinde sadece yazabilirsiniz a+b+c >= 2(ya !!a+!!b+!!c >= 2da çok güvenli olabilirsiniz).

TofuBeer'ın java bayt kodu karşılaştırmasına yanıt olarak , basit bir performans testi aşağıdadır :

class Main
{
    static boolean majorityDEAD(boolean a,boolean b,boolean c)
    {
        return a;
    }

    static boolean majority1(boolean a,boolean b,boolean c)
    {
        return a&&b || b&&c || a&&c;
    }

    static boolean majority2(boolean a,boolean b,boolean c)
    {
        return a ? b||c : b&&c;
    }

    static boolean majority3(boolean a,boolean b,boolean c)
    {
        return a&b | b&c | c&a;
    }

    static boolean majority4(boolean a,boolean b,boolean c)
    {
        return (a?1:0)+(b?1:0)+(c?1:0) >= 2;
    }

    static int loop1(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority1(data[i], data[j], data[k])?1:0; 
                sum += majority1(data[i], data[k], data[j])?1:0; 
                sum += majority1(data[j], data[k], data[i])?1:0; 
                sum += majority1(data[j], data[i], data[k])?1:0; 
                sum += majority1(data[k], data[i], data[j])?1:0; 
                sum += majority1(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static int loop2(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority2(data[i], data[j], data[k])?1:0; 
                sum += majority2(data[i], data[k], data[j])?1:0; 
                sum += majority2(data[j], data[k], data[i])?1:0; 
                sum += majority2(data[j], data[i], data[k])?1:0; 
                sum += majority2(data[k], data[i], data[j])?1:0; 
                sum += majority2(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static int loop3(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority3(data[i], data[j], data[k])?1:0; 
                sum += majority3(data[i], data[k], data[j])?1:0; 
                sum += majority3(data[j], data[k], data[i])?1:0; 
                sum += majority3(data[j], data[i], data[k])?1:0; 
                sum += majority3(data[k], data[i], data[j])?1:0; 
                sum += majority3(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static int loop4(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majority4(data[i], data[j], data[k])?1:0; 
                sum += majority4(data[i], data[k], data[j])?1:0; 
                sum += majority4(data[j], data[k], data[i])?1:0; 
                sum += majority4(data[j], data[i], data[k])?1:0; 
                sum += majority4(data[k], data[i], data[j])?1:0; 
                sum += majority4(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static int loopDEAD(boolean[] data, int i, int sz1, int sz2)
    {
        int sum = 0;
        for(int j=i;j<i+sz1;j++)
        {
            for(int k=j;k<j+sz2;k++)
            {
                sum += majorityDEAD(data[i], data[j], data[k])?1:0; 
                sum += majorityDEAD(data[i], data[k], data[j])?1:0; 
                sum += majorityDEAD(data[j], data[k], data[i])?1:0; 
                sum += majorityDEAD(data[j], data[i], data[k])?1:0; 
                sum += majorityDEAD(data[k], data[i], data[j])?1:0; 
                sum += majorityDEAD(data[k], data[j], data[i])?1:0; 
            }
        }
        return sum;
    }

    static void work()
    {
        boolean [] data = new boolean [10000];
        java.util.Random r = new java.util.Random(0);
        for(int i=0;i<data.length;i++)
            data[i] = r.nextInt(2) > 0;
        long t0,t1,t2,t3,t4,tDEAD;
        int sz1 = 100;
        int sz2 = 100;
        int sum = 0;

        t0 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop1(data, i, sz1, sz2);

        t1 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop2(data, i, sz1, sz2);

        t2 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop3(data, i, sz1, sz2);

        t3 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loop4(data, i, sz1, sz2);

        t4 = System.currentTimeMillis();

        for(int i=0;i<data.length-sz1-sz2;i++)
            sum += loopDEAD(data, i, sz1, sz2);

        tDEAD = System.currentTimeMillis();

        System.out.println("a&&b || b&&c || a&&c : " + (t1-t0) + " ms");
        System.out.println("   a ? b||c : b&&c   : " + (t2-t1) + " ms");
        System.out.println("   a&b | b&c | c&a   : " + (t3-t2) + " ms");
        System.out.println("   a + b + c >= 2    : " + (t4-t3) + " ms");
        System.out.println("       DEAD          : " + (tDEAD-t4) + " ms");
        System.out.println("sum: "+sum);
    }

    public static void main(String[] args) throws InterruptedException
    {
        while(true)
        {
            work();
            Thread.sleep(1000);
        }
    }
}

Bu, makinemde aşağıdakileri yazdırır (HotSpot Server VM ile Intel Core 2 + sun java 1.6.0_15-b03 üzerinde Ubuntu çalışıyor) (14.1-b02, karışık mod):

Birinci ve ikinci tekrarlar:

a&&b || b&&c || a&&c : 1740 ms
   a ? b||c : b&&c   : 1690 ms
   a&b | b&c | c&a   : 835 ms
   a + b + c >= 2    : 348 ms
       DEAD          : 169 ms
sum: 1472612418

Sonraki iterasyonlar:

a&&b || b&&c || a&&c : 1638 ms
   a ? b||c : b&&c   : 1612 ms
   a&b | b&c | c&a   : 779 ms
   a + b + c >= 2    : 905 ms
       DEAD          : 221 ms

Acaba, java VM'nin (a + b + c> = 2) durumu için zaman içindeki performansı düşüren ne yapabilirdi .

Ve bir -clientVM anahtarı ile java çalıştırırsam ne olur :

a&&b || b&&c || a&&c : 4034 ms
   a ? b||c : b&&c   : 2215 ms
   a&b | b&c | c&a   : 1347 ms
   a + b + c >= 2    : 6589 ms
       DEAD          : 1016 ms

Gizem ...

Ve eğer GNU Java Interpreter'de çalıştırırsam , neredeyse 100 kat yavaşlar, ancak a&&b || b&&c || a&&csürüm o zaman kazanır.

En son OS X çalıştıran Tofubeer sonuçları:

a&&b || b&&c || a&&c : 1358 ms
   a ? b||c : b&&c   : 1187 ms
   a&b | b&c | c&a   : 410 ms
   a + b + c >= 2    : 602 ms
       DEAD          : 161 ms

Mac Java 1.6.0_26-b03-383-11A511 ile Paul Wagland sonuçları

a&&b || b&&c || a&&c : 394 ms 
   a ? b||c : b&&c   : 435 ms
   a&b | b&c | c&a   : 420 ms
   a + b + c >= 2    : 640 ms
   a ^ b ? c : a     : 571 ms
   a != b ? c : a    : 487 ms
       DEAD          : 170 ms

4
a+b+c >= 2: negatiflerle çalışmaz, değil mi? Bunu yapmak zorunda olabilirsin, !!aemin değilim.
poligenelubricants

8
<s> 1. Bunu C için asla yapmamalısın. True değerinin ne olduğunu bilmiyorsun (aynı -1 kadar kolay olabilir). </s> Aslında C99'un standardında true'nun 1 olarak tanımlandığını içeriyor. Ama Bunu hala yapmam.
Mark Peters

1
Girdiniz boole işlemlerinden kaynaklanıyorsa bu mümkün müdür? Ve bu C ++ "bool" türü için mümkün mü?
Rotsor

2
@Rotsor: Kimse girdinin boole işlemlerinin bir sonucu olması gerektiğini söylemedi. Negatif olmadan bile ateşle oynuyorsunuz, sanki 2 olarak tanımlamışsınız gibi durumunuzun yanlış pozitifleri olacaktır. Ama booleanın aritmetiğe karışması fikrinden hoşlanmadığım kadar umrumda değil. Java çözümünüz, boole'den tamsayı türüne kadar nüanslı dönüşümlere dayanmadığı için açıktır.
Mark Peters


143

Bu tür sorular Karnaugh Haritası ile çözülebilir :

      | C | !C
------|---|----
 A  B | 1 | 1 
 A !B | 1 | 0
!A !B | 0 | 0
!A  B | 1 | 0

ilk sıra için bir gruba ve ilk sütun için iki gruba ihtiyacınız olduğunu ve poligenel-yağlayıcıların optimal çözümünü elde etmenizi istersiniz:

(C && (A || B)) || (A && B)  <---- first row
       ^
       |
   first column without third case

10
Justin, Karnaugh haritası mantıksal işlem sayısını 3 VE 2 OR'den 2 AND ve 2 OR'ye düşürdü. @Jack, Karnaugh Haritasının varlığını hatırlattığın için teşekkürler.
Taşi

14
Yeni bir şey için +1. Bir sonraki fonksiyonel spesifikasyonum, ister ihtiyacı olsun ister olmasın, bir K-haritası içerecektir.
Justin R.

2
Belki düşük okunabilirlik, (1) yorumdaki uygun tablo ve (2) okulda öğrenilen yararlı bir şey için uygun birim testi ... +1 ile telafi edilebilir.
moala

140

Amaç okunabilirlik olmalıdır. Kodu okuyan biri derhal niyetinizi anlamalıdır. İşte benim çözümüm.

int howManyBooleansAreTrue =
      (a ? 1 : 0)
    + (b ? 1 : 0)
    + (c ? 1 : 0);

return howManyBooleansAreTrue >= 2;

21
Bu önermeye katılıyorum, ama (a && b) || (b && c) || (a && c) IMHO çözümünüzden çok daha okunabilir.
Adrian Grigore

62
Hmm, şimdi "DÖRT booleandan ikisi" versiyonuna ihtiyacım var ... danatel'in versiyonu şimdi çok daha kolay.
Arafangion

6
Veya Scala'da:Seq(true, true, false).map(if (_) 1 else 0).sum >= 2
Retronym

5
@retronym: Hmm, hayır. Java yolu Scala'da gayet iyi çalışıyor ve hem daha okunabilir hem de daha verimli.
Seun Osewa

134
return (a==b) ? a : c;

Açıklama:

Eğer a==böyleyse, ikisi de doğrudur ya da ikisi de yanlıştır. Her ikisi de doğruysa, iki gerçek boolean'ımızı bulduk ve (geri dönerek a) doğru dönebiliriz . Her ikisi de yanlışsa c, doğru olsa bile iki gerçek boolean olamaz , bu yüzden yanlış döndürür (döndürerek a). Bu (a==b) ? akısım. Ne olmuş : c? Eğer a==byanlışsa, o zaman tam olarak doğru aveya bdoğru olmalıdır, bu yüzden ilk gerçek boolean'ı bulduk ve önemli olan tek şey cde doğru ise , doğrudur, bu yüzden ccevap olarak geri döneriz.


8
c asla test bile edilmez ... parlak!
CurtainDog

Eşitlik ve
booleanın

3
Çok şık! İnanmak için kalem ve kağıt ile kontrol etmek zorunda kaldım :) Sana Kudos efendim!
Adrian

3
Ben bunu "eğer kabul et ave bkabul et, çoğunluk oyuna sahipler, bu yüzden ne olursa olsun git, başka bir fikre katılmıyorlar, ckarar oyu da öyle" diye düşünüyorum
Ben Millwood

34

Operatörlerin kısa devre formlarını kullanmanıza gerek yoktur.

return (a & b) | (b & c) | (c & a);

Bu, sürümünüzle aynı sayıda mantık işlemi gerçekleştirir, ancak tamamen dalsızdır.


11
1'in ne zaman yapabileceğini neden 5 değerlendirmeyi zorlamak istersiniz? Gerçekte aynı sayıda mantık işlemi gerçekleştirmez. Aslında, her zaman daha fazlasını yapar.
Mark Peters

2
Bence ikili aritmetik ve boole aritmetiği karıştırmak kötü bir fikirdir. Bir anahtarla duvardaki vidaları sürmek gibidir. En kötüsü de farklı semantikleri var.
Peter Tillemans

12
@ Mark - CPU boru hattı üzerindeki yanlış bir dal tahmininin etkisine bağlı olarak daha hızlı olabilir. Ancak, bu mikro optimizasyonları JIT derleyicisine bırakmak en iyisidir.
Stephen C

4
Java'da (veya başka bir dilde) böyle bir şey yapmak iyidir ... birkaç uyarı ile: 1) daha hızlı olması gerekir (bu durumda, inanıyorum, ikinci cevabımı gör) 2) tercih edilir önemli ölçüde daha hızlı (emin değilim), 3) en önemlisi "tek" olduğu için belgelenmiştir. Bir amaca hizmet ettiği ve belgelendiği sürece mantıklı olduğunda "kuralları çiğnemek" iyidir.
TofuBeer

11
@Peter Tillemans İkili operatörlerle karıştırma yoktur, Java'da bunlar boole operatörleridir.
starblue

27

İşte test odaklı, genel bir yaklaşım. Şimdiye kadar sunulan çözümlerin çoğu kadar "verimli" değil, açık, test edilmiş, çalışıyor ve genelleştirilmiş.

public class CountBooleansTest extends TestCase {
    public void testThreeFalse() throws Exception {
        assertFalse(atLeastTwoOutOfThree(false, false, false));
    }

    public void testThreeTrue() throws Exception {
        assertTrue(atLeastTwoOutOfThree(true, true, true));
    }

    public void testOnes() throws Exception {
        assertFalse(atLeastTwoOutOfThree(true, false, false));
        assertFalse(atLeastTwoOutOfThree(false, true, false));
        assertFalse(atLeastTwoOutOfThree(false, false, true));
    }

    public void testTwos() throws Exception {
        assertTrue(atLeastTwoOutOfThree(false, true, true));
        assertTrue(atLeastTwoOutOfThree(true, false, true));
        assertTrue(atLeastTwoOutOfThree(true, true, false));
    }

    private static boolean atLeastTwoOutOfThree(boolean b, boolean c, boolean d) {
        return countBooleans(b, c, d) >= 2;
    }

    private static int countBooleans(boolean... bs) {
        int count = 0;
        for (boolean b : bs)
            if (b)
                count++;
        return count;
    }
}

8
Vay, bunu görmeden önce hiçbir zaman tam olarak test edilmiş bir yöntem görmedim .
Rotsor

51
Şahsen bu kodu çok fazla nedenden dolayı korkunç buluyorum. Ben küçülmeyeceğim, ama bunu üretim kodunda görürsem lanet ederim. Son derece basit bir boolean işleminin böyle karmaşık olması gerekmez.
CaptainCasey

10
Sebeplerinizi bilmek isterim @CaptainCasey. Bence bu oldukça iyi bir kod. Anlaşılması kolay, doğrulanması kolay ve bundan faydalanan belirli bir işlev, anlaşılması ve doğrulanması kolay güzel bir genel işlev vardır. Gerçek dünyada, onları halka açıp başka bir sınıfa yerleştirirdim; bunun dışında - bu kodu mutlu bir şekilde üretime sokarım. Oh - evet - countBooleans () öğesini countTrue () olarak yeniden adlandırırdım.
Carl Manaster

5
performansla ilgili değilse, bu çözüm benim için neredeyse mükemmel görünüyor: okunması çok kolay ve genişletilebilir. Tam olarak ne var-args ne için yapılır.
atamanroman

7
Ne oluyor insanlar? Bu açık ve iyi test edilmiş bir koddur ve çok benzemesinin tek nedeni testleri içermesidir. A +++, tekrar yükselir.
Christoffer Hammarström

24

Özetle. Bir sebepten dolayı boole cebiri denir:

  0 x 0 = 0
  1 x 0 = 0
  1 x 1 = 1

  0 + 0 = 0
  1 + 0 = 1
  1 + 1 = 0 (+ carry)

Oradaki doğruluk tablolarına bakarsanız, çarpmanın boolean ve basitçe eklemenin xor olduğunu görebilirsiniz.

Soruna cevap vermek için:

return (a + b + c) >= 2

2
Bence bu en şık çözüm.
Torbjørn Kristoffersen

9
Çaylak hatası olsa da, bir boole değeri 0 DEĞİLDİR, bu her zaman 1 anlamına gelmez.
tomdemuyt

13
Mesajdaki etiketin "Java" yazması ve Java'da boolean olarak tanımlandıklarında "a + b + c" yazamazsınız.
Jay

Java'da çalışmak için olması gerekirdi return ((a?1:0) + (b?1:0) + (c?1:0)) >= 2.
David R Tribble

Duh, buna C ++ sorusu olduğunu düşündüğüm için oy verdim ... neden java sorularını okuyorum? : /
Carlo Wood

15
boolean atLeastTwo(boolean a, boolean b, boolean c) 
{
  return ((a && b) || (b && c) || (a && c));
}

15

"Geliştirilmiş" ile gerçekten ne demek istediğinize bağlı:

Daha net?

boolean twoOrMoreAreTrue(boolean a, boolean b, boolean c)
{
    return (a && b) || (a && c) || (b && c);
}

Terser?

boolean moreThanTwo(boolean a, boolean b, boolean c)
{
    return a == b ? a : c;
}

Daha genel?

boolean moreThanXTrue(int x, boolean[] bs)
{
    int count = 0;

    for(boolean b : bs)
    {
        count += b ? 1 : 0;

        if(count > x) return true;
    }

    return false;
}

Daha ölçeklenebilir mi?

boolean moreThanXTrue(int x, boolean[] bs)
{
    int count = 0;

    for(int i < 0; i < bs.length; i++)
    {
        count += bs[i] ? 1 : 0;

        if(count > x) return true;

        int needed = x - count;
        int remaining = bs.length - i;

        if(needed >= remaining) return false;
    }

    return false;
}

Daha hızlı?

// Only profiling can answer this.

Hangisinin "geliştirildiği" büyük ölçüde duruma bağlıdır.


14

Map / reduce kullanan başka bir uygulama. Bu , dağıtılmış bir ortamda milyarlarca boolean © ile iyi ölçeklendirilir . MongoDB'yi kullanma:

valuesBooleans veritabanı oluşturma :

db.values.insert({value: true});
db.values.insert({value: false});
db.values.insert({value: true});

Harita oluşturma, işlevleri azaltma:

Düzenleme : Genel listeler için harita / azaltma uygulamak hakkında CurtainDog yanıtını seviyorum , bu yüzden burada bir değerin sayılması gerekip gerekmediğini belirleyen bir geri arama alır bir harita işlevi gider.

var mapper = function(shouldInclude) {
    return function() {
        emit(null, shouldInclude(this) ? 1 : 0);
    };
}

var reducer = function(key, values) {
    var sum = 0;
    for(var i = 0; i < values.length; i++) {
        sum += values[i];
    }
    return sum;
}

Koşu haritası / azaltma:

var result = db.values.mapReduce(mapper(isTrue), reducer).result;

containsMinimum(2, result); // true
containsMinimum(1, result); // false


function isTrue(object) {
    return object.value == true;
}

function containsMinimum(count, resultDoc) {
    var record = db[resultDoc].find().next();
    return record.value >= count;
}

@Anurag: M / R'yi ve Google'ın son zamanlarda verdiği pozlamayı (FP'den gerçek bir M / R olmasa bile) ne kadar çok sevsem de, cevabınızda bullsh! T deme eğilimindeydim. Tek bir harita / indirgeme satırı kullanılmadığı Real-World [TM] "şeyler" i gerçekleştiren milyarlarca ve milyarlarca satır kod vardır. İle böyle bir soruya cevap Birisi bu : kesinlikle olarak kitabımda işaretlenir "smartie oynamaya çalışıyor" . Çoğu görüşmecinin onlara saçmalamaya çalışıp çalışmadığınızı söyleyemeyeceği için, kariyerinde M / R kullanarak hiçbir zaman tek bir program yazmamışlardır.
SyntaxT3rr0r

2
@Syntax - Herkesin görüşüne hakkı vardır. Cevabım soruna bakmak için sadece bir yaklaşım daha. Elbette, 3 booleans değeri için abartılı geliyor, ama bu burada smarty pantolon olmaya çalıştığım anlamına gelmiyor. Bu, herkesin kullandığı problem çözme için ortak bir yaklaşımdır - sorunu küçük parçalara ayırın. Matematiksel tümevarım bu şekilde çalışır, özyinelemeli algoritmaların çoğu bu şekilde çalışır ve insanlar genel olarak problemleri bu şekilde çözer.
Anurag

13

Cevapları (şimdiye kadar) burada almak:

public class X
{
    static boolean a(final boolean a, final boolean b, final boolean c)
    {
    return ((a && b) || (b && c) || (a && c));
    }

    static boolean b(final boolean a, final boolean b, final boolean c)
    {
    return a ? (b || c) : (b && c);
    }

    static boolean c(final boolean a, final boolean b, final boolean c)
    {
    return ((a & b) | (b & c) | (c & a));
    }

    static boolean d(final boolean a, final boolean b, final boolean c)
    {
    return ((a?1:0)+(b?1:0)+(c?1:0) >= 2);
    }
}

ve bunları kod çözücüden geçirme (javap -c X> results.txt):

Compiled from "X.java"
public class X extends java.lang.Object{
public X();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

static boolean a(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    8
   4:   iload_1
   5:   ifne    24
   8:   iload_1
   9:   ifeq    16
   12:  iload_2
   13:  ifne    24
   16:  iload_0
   17:  ifeq    28
   20:  iload_2
   21:  ifeq    28
   24:  iconst_1
   25:  goto    29
   28:  iconst_0
   29:  ireturn

static boolean b(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    20
   4:   iload_1
   5:   ifne    12
   8:   iload_2
   9:   ifeq    16
   12:  iconst_1
   13:  goto    33
   16:  iconst_0
   17:  goto    33
   20:  iload_1
   21:  ifeq    32
   24:  iload_2
   25:  ifeq    32
   28:  iconst_1
   29:  goto    33
   32:  iconst_0
   33:  ireturn

static boolean c(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   iload_1
   2:   iand
   3:   iload_1
   4:   iload_2
   5:   iand
   6:   ior
   7:   iload_2
   8:   iload_0
   9:   iand
   10:  ior
   11:  ireturn

static boolean d(boolean, boolean, boolean);
  Code:
   0:   iload_0
   1:   ifeq    8
   4:   iconst_1
   5:   goto    9
   8:   iconst_0
   9:   iload_1
   10:  ifeq    17
   13:  iconst_1
   14:  goto    18
   17:  iconst_0
   18:  iadd
   19:  iload_2
   20:  ifeq    27
   23:  iconst_1
   24:  goto    28
   27:  iconst_0
   28:  iadd
   29:  iconst_2
   30:  if_icmplt   37
   33:  iconst_1
   34:  goto    38
   37:  iconst_0
   38:  ireturn
}

?: Bunların orijinalinizin sabitlenmiş versiyonundan biraz daha iyi olduğunu görebilirsiniz. En iyisi dallanmayı tamamen önleyen olandır. Bu, daha az talimat açısından (çoğu durumda) iyidir ve CPU'nun dal tahmin bölümleri için daha iyidir, çünkü dal tahmininde yanlış bir tahmin CPU durmasına neden olabilir.

En verimli olanının genel olarak moonshadow'dan olduğunu söyleyebilirim. Ortalama olarak en az talimat kullanır ve CPU'da boru hattı duraklama şansını azaltır.

% 100 emin olmak için her talimatın maliyetini (CPU döngülerinde) bulmanız gerekecek, bu da maalesef hazır değil (hotspot kaynağına ve daha sonra CPU satıcılarının spesifikasyonlarına bakmanız gerekecek) oluşturulan her talimat için alınır).

Kodun çalışma zamanı analizi için Rotsor'un güncel yanıtına bakın.


5
Sadece bayt koduna bakıyorsunuz. Bildiğiniz her şey için, JIT bayt kodunda şubeleri olan bir sürümü alacak ve yerel kodda şubesi olmayan bir sürüme dönüştürecektir. Ancak bayt koddaki daha az dalın daha iyi olacağını düşünmek eğilimindedir.
David Conrad

13

Doğrudan kodun başka bir örneği:

int  n = 0;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 2);

Açıkçası, en özlü kod bu değil.

ek

Bunun başka bir (biraz optimize edilmiş) sürümü:

int  n = -2;
if (a) n++;
if (b) n++;
if (c) n++;
return (n >= 0);

Bu, 0 ile karşılaştırmanın 2 ile karşılaştırmadan daha hızlı (veya belki daha az) kod kullanacağını varsayarak biraz daha hızlı çalışabilir.


+1 @Loadmaster, üzgünüm ama yanılıyorsun! Buradaki en özlü cevap bu. (yani kısaca VE açıkça ifade edilir);)
Ash


@ M.Mimpen: Yalnızca sınıf nesneleri için. İlkel tipler için ( nyukarıdaki gibi), herhangi bir iyi derleyici, ++ön veya son olsun, her işlemi tek bir CPU komutuna derleyecektir .
David R Tribble

12

Bunu yapmanın başka bir yolu ama çok iyi değil:

return (Boolean.valueOf(a).hashCode() + Boolean.valueOf(b).hashCode() + Boolean.valueOf(c).hashCode()) < 3705);

BooleanKarma kodu değerleri aynı kullanılmış olabilir yanlış olarak için de geçerlidir ve 1237 için 1231 sabitlenir<= 3699


1
veya (a? 1: 0) + (b? 1: 0) + (c? 1: 0)> = 2
Peter Lawrey

12

En belirgin iyileştirmeler şunlardır:

// There is no point in an else if you already returned.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a && b) || (b && c) || (a && c)) {
        return true;
    }
    return false;
}

ve sonra

// There is no point in an if(true) return true otherwise return false.
boolean atLeastTwo(boolean a, boolean b, boolean c) {
    return ((a && b) || (b && c) || (a && c));
}

Ancak bu gelişmeler azdır.


10

Üçlü ( return a ? (b || c) : (b && c);en iyi cevaptan) hoşlanmıyorum ve kimsenin bahsettiğini gördüğümü sanmıyorum. Bu şekilde yazılmıştır:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if (a) {
        return b||c;
    } 
    else {
        return b&&C;
    }

8

In Clojure :

(defn at-least [n & bools]
  (>= (count (filter true? bools)) n)

Kullanımı:

(at-least 2 true false true)

2
+1 Büyük genel sürüm Lisps'in gücünü gösterir. Teşekkürler,
dsmith

6

Bu çözümü henüz gördüğümü sanmıyorum:

boolean atLeast(int howMany, boolean[] boolValues) {
  // check params for valid values

  int counter = 0;
  for (boolean b : boolValues) {
    if (b) {
      counter++;

      if (counter == howMany) {
        return true;
      }
    }
  }
  return false;
}

Avantajı, aradığınız sayıya ulaştığında kırılmasıdır. Dolayısıyla, eğer bu ilk ikisinin gerçekten doğru olduğu "bu 1.000.000 değerin en az 2'si doğruysa", daha "normal" çözümlerden bazılarından daha hızlı gitmelidir.


Muhtemelen şöyle olmalıdır: Artırmak ve sonra ayrı ayrı kontrol etmek yerine if (++ counter == howMany).
Joe Enos

2
Veya daha da kısa: if (b && (++ counter == howMany))
Joe Enos

1
Bunu yapmak boolean ... boolValuesdaha kolay olurdu , ama yine de bir dizi alıyor
Stephen

Java'mda güncel değilim - bunun var olduğunu bilmiyordum. Biraz tuhaf bir sözdizimi, ama yararlı - arada bir C # (params anahtar kelime) bunu yapacağım ve aramak için daha güzel hale getirir. Veya, Java hakkında bilmiyorum, ancak .NET'te, diziler ve tüm koleksiyonlar IEnumerable <T> uygular, bu yüzden muhtemelen Java'nın eşdeğeri ne olursa olsun kullanırım.
Joe Enos

Bunun performansı 2of3 örneğiyle nasıl karşılaştırılır? dönüş? (b || c): (b && c);
Iain Sproat

6

Bools'u tamsayılara dönüştürebilir ve bu kolay kontrolü yapabiliriz:

(int(a) + int(b) + int(c)) >= 2

6

Kodun nasıl geliştirilmesi gerektiği belirtilmediğinden, kodu daha eğlenceli hale getirerek geliştirmeye çalışacağım. İşte benim çözümüm:

boolean atLeastTwo(boolean t, boolean f, boolean True) {
    boolean False = True;
    if ((t || f) && (True || False)) 
        return "answer" != "42";
    if (t && f) 
        return !"France".contains("Paris");
    if (False == True) 
        return true == false;
    return Math.random() > 0.5;
}

Herhangi birinin bu kodun çalışıp çalışmadığını merak etmesi durumunda, aynı mantığı kullanan bir basitleştirme:

boolean atLeastTwo(boolean a, boolean b, boolean c) {
    if ((a || b) && (c)) 
        return true;
    if (a && b) 
        return true;
    if (true) 
        return false;
    // The last line is a red herring, as it will never be reached:
    return Math.random() > 0.5; 

}

Bu aşağıdakilere daha da kaynatılabilir:

return ((a || b) && (c)) || (a && b);

Ama şimdi artık komik değil.


5
Function ReturnTrueIfTwoIsTrue(bool val1, val2, val3))
{
     return (System.Convert.ToInt16(val1) +
             System.Convert.ToInt16(val2) +
             System.Convert.ToInt16(val3)) > 1;
}

Bunu yapmanın çok fazla yolu var ...


3
C # gibi görünün. Soru Java hedefli olduğu için bu yanıtta böyle belirtilmelidir :)
BalusC

5

AC çözümü.

int two(int a, int b, int c) {
  return !a + !b + !c < 2;
}

veya aşağıdakileri tercih edebilirsiniz:

int two(int a, int b, int c) {
  return !!a + !!b + !!c >= 2;
}

4
return 1 << $a << $b << $c >= 1 << 2;

Bunu pozlamadan önce Suvega'nın cevabını görmedim, hemen hemen aynı şey.
Kevin

Bu gerçekten işe yarıyor mu? Bu PHP olduğunu varsayalım, ama erişimim yok, ama sadece size soracağım: $ a 0 ise ne olur?
Mark Edgar

@Mark $ a 0 ise işe yaramıyor. Bu bir gözetimdi. Bunu işaret ettiğiniz için teşekkürler. :)
Kevin

4

Kafa karıştırıcı ve okunması kolay olmayan en basit yol (IMO):

// Three booleans, check if two or more are true

return ( a && ( b || c ) ) || ( b && c );

İşlevsel olarak, aynı. Sözdizimsel olarak, soru işareti koşullu operatörün kullanımına alışık olmayanlar için okumayı kolaylaştırır. Soru işareti koşullu operatörleri kullanmayı bilenlerin sayısından daha fazla VE ve VEYA operatörünün nasıl kullanılacağını bildiklerine bahse girmeye hazırım. Asıl soru “geliştirilmiş cevap” ister. Kabul edilen cevap cevabı basitleştirir, ancak neyin iyileştirmeyi düşündüğü konusunda çok ilginç bir soru ortaya çıkarır. Evrensel okunabilirlik mi yoksa basitlik için mi programlıyorsunuz? Benim için, bu kabul edilen cevap üzerinde bir gelişme :)
abelito

Kişisel tercihler. Benim için daha temiz üçlü operatörü anlamak bu çözümden çok daha kolay.
nico

1
Ah evet, bu sorunu gördüm ve neden başka hiç kimsenin bu çözümden bahsetmediğini merak ediyordum. OP'nin mantığını boole cebiri olarak yazarsanız , beş işlemi olan A B + A C + B C alırsınız . İlişkilendirme özelliğine göre, dört işlemi olan A * (B + C) + B C yazabilirsiniz .
Vivian River

Jack'in (C && (A || B)) || (A && B)
yanıtıyla

4

Gerçek bir yorum tüm ana dillerde çalışacaktır:

return (a ? 1:0) + (b ? 1:0) + (c ? 1:0) >= 2;

Ama muhtemelen insanların okumasını kolaylaştıracak ve üçten fazlaya genişletilebilir - birçok programcı tarafından unutulmuş gibi görünüyor:

boolean testBooleans(Array bools)
{
     int minTrue = ceil(bools.length * .5);
     int trueCount = 0;

     for(int i = 0; i < bools.length; i++)
     {
          if(bools[i])
          {
               trueCount++;
          }
     }
     return trueCount >= minTrue;
}

4

@TofuBeer TofuBeer'in mükemmel gönderisine ek olarak, @pdox pdox'un cevabını düşünün:

static boolean five(final boolean a, final boolean b, final boolean c)
{
    return a == b ? a : c;
}

Ayrıca "javap -c" tarafından verilen demonte versiyonunu da göz önünde bulundurun:

static boolean five(boolean, boolean, boolean);
  Code:
    0:    iload_0
    1:    iload_1
    2:    if_icmpne    9
    5:    iload_0
    6:    goto    10
    9:    iload_2
   10:    ireturn

pdox'un yanıtı, önceki yanıtların herhangi birinden daha az bayt kodla derlenir. Uygulama süresi diğerleriyle nasıl karşılaştırılır?

one                5242 ms
two                6318 ms
three (moonshadow) 3806 ms
four               7192 ms
five  (pdox)       3650 ms

En azından bilgisayarımda, pdox'un cevabı @moonshadow moonshadow'un cevabından biraz daha hızlı, pdox'u genel olarak en hızlı (HP / Intel dizüstü bilgisayarımda) yapıyor.


3

Ruby'de:

[a, b, c].count { |x| x } >= 2

Hangi JavaVM JRuby çalıştırılabilir. ;-)


3

Muhtemelen bitsel karşılaştırma operatörleri (normalde kıvrık değil, booleanlarla, bitsel operatörleri kullanmak son derece garip) veya int'e dönüştürmek ve onları toplamak gibi çok dolambaçlı bir şey gibi kıvrımlı bir şey aramıyor.

Bunu çözmenin en doğrudan ve doğal yolu şöyle bir ifadedir:

a ? (b || c): (b && c)

İsterseniz bir işleve koyun, ancak çok karmaşık değil. Çözüm mantıklı ve özlüdür.


3

C dilinde:

return !!a + !!b + !!c >= 2;

Aslında, bu cevap yanlıştır…> 2 olmalıdır, çünkü tam olarak iki değil, en az iki gerçek boole ihtiyacınız vardır .
Paul Wagland

@ Paul Wagland: Yakaladığınız için teşekkürler.
Matt Joiner

@ergosys: İki kere cevapladım mı?
Matt Joiner
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.