부울 3 개 중 2 개 이상이 true인지 확인


579

한 면접관이 최근에이 질문을했습니다. 세 개의 부울 변수 a, b 및 c가 주어지면 세 개 중 두 개 이상이 참이면 true를 반환합니다.

내 해결책은 다음과 같습니다.

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

그는 이것이 더 개선 될 수 있다고 말했다. 그러나 어떻게?


170
리턴 문을 인라인하십시오.
Finglas

45
"IQ가 가장 높은 사람"인터뷰처럼 들립니다. 나는 실패 할 것이다.
Chris Dutrow

79
atLeastTwo(iWantYou, iNeedYou, imEverGonnaLoveYou)
Andrew Grimm

92
사람들이 가장 사소한 질문을하는 이유는 무엇입니까?
BlueRaja-대니 Pflughoeft

46
일반적이고 이해하기 쉬운 질문은 많은 투표를 얻습니다. 매우 구체적이고 기술적 인 질문은 그렇지 않습니다.
Jay

답변:


820

쓰기보다는 :

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

쓰다:

return someExpression;

표현 자체는 다음과 같습니다.

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

또는 이것 (쉽게 파악하기 쉬운 것) :

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

그것은 테스트 ab정확히 한 번, 그리고 c대부분 한 번에.

참고 문헌


144
+1 : 퍼즐에 대한 멋진 해결책이지만, 현실 세계에서 이런 것을 보지 않기를 바랍니다. :)
Juliet

124
@ 줄리엣 : 모르겠습니다. 이것이 실제 변수 이름을 가진 실제 요구 사항이라면 꽤 잘 읽을 것이라고 생각합니다. 고려해보십시오 return hasGoodAttendance ? (passedCoursework || passed Exam) : (passedCoursework && passedExam).
Andrzej Doyle

18
나는 그것이 나빠 보이지 않는다고 생각 하지만, 도메인의 요구 사항이 "적어도 2"인 것으로 이해된다면, 읽기가 더 쉽다고 생각합니다 atLeastTwo(hasgoodAttendance, passedCoursework, passedExam). "적어도 2 개의 bools가 사실"이라는 아이디어는 그 자체 기능을 수행 할 수있을 정도로 일반적입니다.
Ken

17
@Lese : 직접 대면 인터뷰에서 가장 미세하게 최적화 된 코드를 요청하는 것은 실용적이지 않으며 감히 쓸모없는 말입니다. 요구에 따라 미세 최적화는 인간 본능 (끔찍한 것으로 알려진)이 아닌 런타임 프로파일 링 결과에 의해 유도됩니다. 당신은 확실히 당신이 이것을 더 최적화하는 과정을 인터뷰 대상에게 요청할 수 있습니다; 결과 자체보다 더 중요합니다.
polygenelubricants

17
삼항 연산자는 읽을 수있는 일반적인 관용구입니다. 읽을 수 없다면 가능할 때까지 공부해야합니다. 삼항 연산자를 사용하는 것은 필사적 인 의미에서 "영리한"것으로 간주되는 것이 아닙니다. 그러나 네, 일반적으로 "적어도 2 개"논리를 사용하는 경우이 메소드를 메소드 호출의 본문으로 지정합니다.
Stephen P

493

XOR을 사용하여 비교적 간단한 문제에 대답하기 위해 ...

return a ^ b ? c : a

159
와우, 멋진 솔루션. 그러나 나를 위해 반전 된 버전을 이해하기가 더 쉽습니다. a == b? a : c
Rotsor

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

4
예, XOR은 그런 나쁜 언론을 얻지 못하고 거의 그것을 사용할 기회를 얻지 못합니다.
EightyOne Unite

18
@ Stimul8d는 부울의 경우! =와 동일하지만 읽기 쉽지 않기 때문에 어쩌면? 나를 위해 유레카의 순간 ... 그 아웃했다내는
티콘 Jelvis

2
나는 순수한 이진 형식을 선호합니다 : return ((a ^ b) & c) | (a & b). 분기가 없으며 (빠르고) 읽기 쉽습니다 : (a 또는 b는 true이고 c는 true) 또는 (a와 b는 모두 true) (a | b) 및 (a ^ b)는 모두이 공식에서 작동합니다.
flanglet

217

문자 그대로 구현하지 않겠습니까? :)

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

C에서는 작성 a+b+c >= 2하거나 !!a+!!b+!!c >= 2매우 안전 할 수 있습니다.

에 대한 응답으로 TofuBeer 자바 바이트 코드의 비교, 여기에 간단한 성능 테스트는 다음과 같습니다

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);
        }
    }
}

내 컴퓨터에서 다음을 인쇄합니다 (핫스팟 서버 VM (14.1-b02, 혼합 모드)으로 Intel Core 2 + sun java 1.6.0_15-b03에서 Ubuntu 실행) :

첫 번째와 두 번째 반복 :

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

나중에 반복 :

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

(a + b + c> = 2) 사례에 대해 시간이 지남에 따라 성능 을 저하시키는 Java VM의 기능은 무엇입니까 ?

그리고 -clientVM 스위치로 java를 실행하면 어떻게됩니까?

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

신비...

그리고 GNU Java Interpreter 에서 실행 하면 거의 100 배 느려지지만 a&&b || b&&c || a&&c버전이 승리합니다.

OS X를 실행하는 최신 코드를 사용한 Tofubeer의 결과 :

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을 사용한 Paul Wagland의 결과

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: 이것은 부정적인면에서는 효과가 없습니다. 당신은 !!a일 을해야 할 수도 있습니다 , 확실하지 않습니다.
polygenelubricants 2016 년

8
<s> -1. C의 경우에는 그렇게하지 않아야합니다. true의 값이 무엇인지 모릅니다 (쉽게 -1 일 수 있음). </ s> 실제로 C99에는 표준에 true가 1로 정의되어 있다고 생각합니다. 나는 아직도 이것을하지 않을 것입니다.
Mark Peters

1
입력이 부울 연산의 결과 인 경우 가능합니까? 그리고 C ++에서 "bool"타입도 가능합니까?
Rotsor

2
@Rotsor : 아무도 입력이 부울 연산의 결과 여야한다고 말하지 않았습니다. 네거티브가 없어도 불을 가지고 놀고 있습니다. 마치 2로 정의하는 것처럼 조건은 거짓 긍정입니다. 그러나 부울을 산술로 결합한다는 생각을 싫어하는 한 그것에 대해서는 신경 쓰지 않습니다. Java 솔루션은 부울에서 정수 유형으로의 미묘한 변환에 의존하지 않는다는 점에서 분명합니다.
Mark Peters

7
마이크로 벤치 마크에주의하십시오 : java.sun.com/docs/hotspot/HotSpotFAQ.html#benchmarking_simple
BalusC

143

이런 종류의 질문은 Karnaugh Map 으로 해결할 수 있습니다 .

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

여기에서 첫 번째 행에 대한 그룹과 첫 번째 열에 대한 두 그룹이 필요하다고 판단하여 최적의 다유 윤활제 용액을 얻습니다.

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

10
@Justin, Karnaugh 맵은 논리 연산 수를 3 AND 및 2 OR에서 2 AND 및 2 OR로 줄였습니다. @ 잭, Karnaugh Map의 존재를 상기시켜 주셔서 감사합니다.
Tachy

14
새로운 것을 위해 +1. 다음 기능 사양에는 K-map이 필요할지 여부가 포함됩니다.
Justin R.

2
어쩌면 가독성이 좋지 않은 것은 (1) 적절한 표와 (2) 학교에서 배운 유용한 것에 대한 적절한 단위 시험 ... + 1에 의해 보상 될 수 있습니다.
moala

140

가독성이 목표가되어야합니다. 코드를 읽는 사람은 귀하의 의도를 즉시 이해해야합니다. 그래서 여기 내 해결책이 있습니다.

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

return howManyBooleansAreTrue >= 2;

21
전제에 동의하지만 (a && b) || (b && c) || (a & & c)는 솔루션 IMHO보다 훨씬 더 읽기 쉽습니다.
Adrian Grigore

62
흠, 이제 "4 가지 부울 중 2 개"버전이 필요합니다 ... danatel의 버전이 훨씬 쉬워졌습니다.
Arafangion 2016 년

6
또는 스칼라에서 :Seq(true, true, false).map(if (_) 1 else 0).sum >= 2
retronym

5
@retronym : 흠. Java 방식은 스칼라에서 잘 작동하며 더 읽기 쉽고 효율적입니다.
Seun Osewa

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

설명:

인 경우 a==b둘 다 true이거나 둘 다 false입니다. 둘 다 true이면 두 개의 실제 부울을 찾은 후 true를 반환 할 수 있습니다 (을 반환하여 a). 둘 다 거짓이면 참인 경우에도 두 개의 참 부울이있을 수 c없으므로를 반환하여 거짓을 반환 a합니다. 그 (a==b) ? a부분입니다. 무엇에 대해 : c? 음 a==b이 거짓 이라면 , 정확히 하나 a이거나 b사실이어야합니다. 그래서 우리는 첫 번째 참 부울을 찾았습니다. 그리고 중요한 것은 남은 것이 c사실이기도합니다. 그래서 우리 c는 답으로 돌아갑니다 .


8
c조차도 테스트되지 않았습니다 ... 훌륭합니다!
CurtainDog

평등의 전이 관계와 부울이 참 또는 거짓이라는 사실을 사용합니다.
Christophe Roussy

3
너무 우아합니다! 나는 그것을 믿고 펜과 종이로 확인했다 :) 당신에게 선생님!
Adrian

3
나는 이것에 대해 "만약 동의 한다면 a, b다수의 투표권을 가지므로, 그것이 무엇이든지간에 동의하지 않으면, 그렇지 않은 c결정 투표도 마찬가지 "라고 생각합니다.
Ben Millwood

34

단락 회로 연산자를 사용할 필요는 없습니다.

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

이것은 버전과 동일한 수의 논리 연산을 수행하지만 완전히 분기가 없습니다.


11
1 번 할 수 있는데 왜 5 번의 평가를 강요하고 싶습니까? 실제로 동일한 수의 논리 연산을 수행하지 않습니다. 실제로 항상 더 많은 성능을 발휘합니다.
Mark Peters

2
이진 산술과 부울 산술을 혼합하는 것은 나쁜 생각이라고 생각합니다. 렌치로 벽에 나사를 박는 것과 같습니다. 무엇보다도 최악의 의미가 다릅니다.
Peter Tillemans

12
@Mark-CPU 파이프 라인에 대한 잘못된 분기 예측의 영향에 따라 더 빠를 수 있습니다. 그러나 이러한 미세 최적화를 JIT 컴파일러에 두는 것이 가장 좋습니다.
Stephen C

4
Java (또는 다른 언어)에서 이와 같은 작업을하는 것이 좋습니다 ... 몇 가지주의 사항이 있습니다 .1) 더 빨라야합니다 (이 경우에는 두 번째 대답 참조) 2) 선호 3) "홀수"이므로 가장 중요하게 문서화됩니다. 그것이 목적에 부합하고 문서화되어있는 한, 그것이 적절할 때 "규칙을 어기는"것이 좋습니다.
TofuBeer

11
@Peter Tillemans 이진 연산자와의 혼합은 없으며 Java에서는 부울 연산자입니다.
starblue

27

다음은 테스트 중심의 일반적인 접근 방식입니다. 지금까지 제공된 대부분의 솔루션만큼 "효율적인"것이 아니라 명확하고 테스트되고 작동하며 일반화되었습니다.

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
와우, 나는이 방법을보기 전에 완전히 테스트 된 방법을 본 적이 없습니다 .
Rotsor

51
개인적으로이 코드는 여러 가지 이유로 끔찍합니다. 나는 공감하지 않을 것이지만 프로덕션 코드에서 이것을 본다면 저주 할 것입니다. 매우 간단한 부울 연산은 이와 같이 복잡 할 필요가 없습니다.
CaptainCasey 2016 년

10
@CaptainCasey, 귀하의 이유를 알고 싶습니다. 나는 이것이 꽤 좋은 코드라고 생각합니다. 이해하기 쉽고 검증하기 쉬운 일반화 된 기능과이를 활용하는 특정 기능, 이해 및 검증이 용이합니다. 현실 세계에서 나는 그들을 공개하고 다른 클래스에 넣었습니다. 그 이외의 것-이 코드를 프로덕션 환경에 넣었습니다. 오-그래-countBooleans ()의 이름을 countTrue ()로 바꿨습니다.
Carl Manaster

5
성능에 관한 것이 아니라면이 솔루션은 거의 완벽하게 보입니다. 읽기 쉽고 확장 가능합니다. 바로 var-args가 만들어지는 것입니다.
atamanroman

7
도대체 사람들? 이것은 명확하고 잘 테스트 된 코드이며, 코드가 많이 보이는 유일한 이유는 테스트가 포함되어 있기 때문입니다. A +++, 다시 공표합니다.
Christoffer Hammarström

24

더해. 이유 때문에 부울 대수라고합니다.

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

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

거기에있는 진리표를 보면 곱셈이 부울이며 단순히 덧셈이 xor임을 알 수 있습니다.

질문에 대답하려면 :

return (a + b + c) >= 2

2
이것은 제 생각에 가장 우아한 해결책입니다.
Torbjørn Kristoffersen 2016 년

9
신인 실수, 부울 값이 0이 아닙니다, 그것은 항상 1을 의미하지 않습니다.
tomdemuyt

13
게시물의 태그에 "Java"라고 표시되고 Java에서 부울로 정의 된 경우 "a + b + c"를 쓸 수 없습니다.
Jay

Java로 작업하려면이어야 return ((a?1:0) + (b?1:0) + (c?1:0)) >= 2합니다.
David R Tribble

Duh, 나는 이것이 C ++ 질문이라고 생각했기 때문에 이것을 투표했습니다 ... 왜 Java 질문을 읽고 있습니까? : /
Carlo Wood

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

15

그것은 실제로 "개선"의 의미에 달려 있습니다.

더 깨끗해?

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

터서?

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

더 일반적인?

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

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

        if(count > x) return true;
    }

    return false;
}

더 확장 가능합니까?

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

빨리?

// Only profiling can answer this.

"개선 된"것은 상황에 따라 크게 다릅니다.


14

map / reduce를 사용하는 또 다른 구현이 있습니다. 이 규모도에 부울 수십억 © 분산 환경이다. MongoDB 사용하기 :

values부울 데이터베이스 작성 :

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

맵을 작성하고 기능을 줄입니다.

편집 : map / reduce가 일반 목록에 적용되는 것에 대한 CurtainDog의 답변이 마음에 듭니다 . 따라서 값 계산 여부를 결정하는 콜백을 취하는 map 함수가 있습니다.

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

지도 / 축소 실행 :

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과 Google이 최근에 노출 한 노출 (FP의 진정한 M / R이 아니더라도)을 좋아하는 한, 귀하의 답변에 bullsh! t라고 부르는 경향이 있습니다. 사용 된 단일 맵 / 리 듀스 라인이없는 Real-World ™ "재료"를 수행하는 수십억 라인의 코드가 있습니다. 와 같은 질문에 대답 사람 : 확실히 나의 책에서 플래그가 "를 smartie을 재생하려고합니다" . 대부분의 면접관은 말할 것도없고, 자신의 경력에서 실제로 M / R을 사용하여 단일 프로그램을 작성하지 않았기 때문에 당신이 그들을 강탈하려고하는지 아닌지를 말할 수 없을 것입니다.
SyntaxT3rr0r

2
@ 구문-모든 사람은 자신의 의견을 가질 권리가 있습니다. 내 대답은 문제를 보는 또 하나의 접근 방식입니다. 물론, 그것은 3 개의 부울 값에 대해 과장된 것처럼 들리지만, 이것이 내가 똑똑한 바지가 되려고한다는 것을 의미하지는 않습니다. 이것은 모든 사람이 사용하는 문제 해결에 대한 일반적인 접근 방식입니다. 문제를 작은 조각으로 나눕니다. 그것이 수학적 유도가 작동하는 방식, 가장 재귀적인 알고리즘이 작동하는 방식, 사람들이 일반적으로 문제를 해결하는 방식입니다.
Anurag

13

여기에 (지금까지) 답을 얻으십시오.

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);
    }
}

디 컴파일러를 통해 실행하십시오 (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
}

? :는 원본의 고정 버전보다 약간 낫다는 것을 알 수 있습니다. 가장 좋은 것은 분기를 완전히 피하는 것입니다. 이는 분기 예측의 잘못된 추측이 CPU 정지를 유발할 수 있기 때문에 더 적은 명령어 (대부분의 경우) 관점에서 좋고 CPU의 분기 예측 부분에 더 좋습니다.

가장 효율적인 것은 전반적으로 달 그림자의 것입니다. 평균적으로 가장 적은 명령어를 사용하며 CPU에서 파이프 라인 중단 가능성을 줄입니다.

100 % 확실하게하려면 각 명령어에 대한 비용 (CPU주기)을 알아야합니다. 불행히도 쉽게 사용할 수 없습니다 (핫스팟 소스를 확인한 다음 해당 시간 동안 CPU 공급 업체 사양을 확인해야 함) 생성 된 각 명령에 대해 수행됨).

코드의 런타임 분석에 대해서는 Rotsor의 업데이트 된 답변을 참조하십시오.


5
바이트 코드 만보 고 있습니다. 아시다시피 JIT는 바이트 코드에 분기가있는 버전을 가져 와서 네이티브 코드에 분기가없는 버전으로 바꿉니다. 그러나 바이트 코드에서 더 적은 분기가 더 좋을 것이라고 생각하는 경향이 있습니다.
David Conrad

13

직접 코드의 다른 예 :

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

가장 간결한 코드는 아닙니다.

추가

이것의 또 다른 (약간 최적화 된) 버전 :

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

0에 대한 비교가 2에 대한 비교보다 더 빠르거나 더 적은 코드를 사용한다고 가정하면 약간 더 빠르게 실행될 수 있습니다.


+1 @Loadmaster, 죄송합니다. 잘못되었습니다! 이것은 가장 간결한 답변입니다. (즉, 간단하고 명확하게 표현);)
Ash


@ M.Mimpen : 클래스 객체에만 해당됩니다. 프리미티브 유형 ( n위와 같은)의 경우, 알맞은 컴파일러는 각 ++작업을 사전 또는 사후에 상관없이 단일 CPU 명령어로 컴파일합니다 .
David R Tribble

12

그러나 이것을 수행하는 또 다른 방법이지만 아주 좋은 방법은 아닙니다.

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

Boolean해시 값은 동일하게 사용할 수도 거짓 그래서에 대한 true 및 1237에 대한 1231으로 고정됩니다<= 3699


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

12

가장 확실한 개선 사항은 다음과 같습니다.

// 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;
}

그리고

// 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));
}

그러나 이러한 개선은 미미합니다.


10

나는 ( return a ? (b || c) : (b && c);정답에서) 삼항을 좋아하지 않으며 , 누군가가 그것을 언급 한 것을 본 적이 없다고 생각합니다. 다음과 같이 작성되었습니다.

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

8

에서 Clojure의 :

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

용법:

(at-least 2 true false true)

2
+1 위대한 일반 버전은 리스프의 힘을 보여줍니다. 감사합니다,
dsmith

6

나는이 해결책을 아직 보지 못했다고 생각한다.

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

찾고자하는 숫자에 도달하면 중단됩니다. 따라서 처음 두 개가 실제로 참인 "이 1,000,000 개 값 중 적어도 2 개가 참"인 경우 좀 더 "정상적인"솔루션보다 빠릅니다.


아마 다음과 같아야 할 것입니다 : if (++ counter == howMany) 대신 증가시키고 따로 검사하는 것이 아닙니다.
Joe Enos 2016 년

2
또는 더 짧습니다 : if (b && (++ counter == howMany))
Joe Enos

1
내가 할 줄 boolean ... boolValues은 전화로 쉽게 그래서,하지만 여전히 배열합니다
스티븐

Java에 최신 상태가 아닙니다. 존재하는 줄 몰랐습니다. 이상한 구문이지만 유용합니다. 가끔씩 C # (params 키워드)으로 처리하고 호출하기가 더 좋습니다. 또는 Java에 대해서는 잘 모르지만 .NET에서는 배열 및 모든 컬렉션이 IEnumerable <T>를 구현하므로 Java와 동등한 것이 무엇이든 사용할 것입니다.
Joe Enos

이 성능을 2of3 예제와 어떻게 비교합니까? ?를 반환 (b || c) : (b && c);
Iain Sproat 11

6

bool을 정수로 변환하고 다음과 같은 쉬운 점검을 수행 할 수 있습니다.

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

6

코드를 어떻게 개선해야하는지 지정하지 않았으므로 코드를 더 재미있게 만들어서 개선하려고 노력할 것입니다. 내 해결책은 다음과 같습니다.

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

이 코드가 작동하는지 궁금한 사람이있는 경우 동일한 논리를 사용하여 단순화합니다.

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; 

}

이것은 다음과 같이 더 요약 될 수 있습니다.

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

그러나 이제는 더 이상 재미 있지 않습니다.


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

이렇게하는 방법이 너무 많습니다 ...


3
C #처럼 보입니다. 질문이 Java 대상이기 때문에 답변에서 언급해야합니다 :)
BalusC

5

AC 솔루션.

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

또는 다음을 선호 할 수 있습니다.

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

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

이 포즈를 취하기 전에 Suvega의 대답을 보지 못했습니다.
Kevin

이것이 실제로 작동합니까? 나는 이것이 PHP라고 가정하지만 그것에 액세스 할 수는 없지만 그냥 물어볼 것입니다 : $ a가 0이면 어떻게됩니까?
Mark Edgar

@Mark $ a가 0이면 실제로 작동하지 않습니다. 그것은 감독이었습니다. 지적 해 주셔서 감사합니다. :)
Kevin

4

혼란스럽고 읽기 쉬운 가장 간단한 방법 (IMO) :

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

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

기능적으로는 동일합니다. 문법적으로, 물음표 조건부 연산자를 사용하는 데 익숙하지 않은 사람들은 쉽게 읽을 수 있습니다. 물음표 조건부 연산자를 사용하는 방법을 알고있는 사람보다 AND 및 OR 연산자를 사용하는 방법을 더 많이 알고 싶습니다. 원래 질문은 "개선 된 답변"을 요구합니다. 승인 된 답변은 답변을 단순화하지만 개선을 고려하는 것에 대한 매우 흥미로운 질문을 제기합니다. 보편적 인 가독성 또는 단순성에 대해 프로그래밍합니까? 나에게, 이것은 받아 들인 대답보다 개선되었습니다 :)
abelito

개인 취향. 나를 위해이 솔루션보다 청소기 삼항 연산자를 이해하는 것이 훨씬 쉽습니다.
니코

1
아 그래, 나는이 문제를 보았고 아무도 왜이 솔루션을 언급하지 않았는지 궁금해하고있었습니다. OP의 논리를 부울 대수로 쓰면 5 개의 연산 이있는 A B + A C + B C 를 얻게 됩니다. 연관 속성을 사용하면 네 가지 작업이있는 A * (B + C) + B C를 작성할 수 있습니다 .
Vivian River

Jack의 답변 (6 월 19 일)이 (C && (A || B)) || (A && B)방금 변수 이름을 변경 한 것과
같습니다

4

문자 그대로의 해석은 모든 주요 언어로 작동합니다.

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

그러나 아마도 사람들이 읽기 쉽고 3 개 이상으로 확장 할 수있게 만들 것입니다. 많은 프로그래머가 잊어 버린 것 같습니다.

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의 우수 게시물에 덧붙여 @pdox pdox의 답변을 고려하십시오.

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

"javap -c"에 제공된대로 분해 된 버전도 고려하십시오.

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의 답변은 이전 답변보다 적은 바이트 코드로 컴파일됩니다. 실행 시간은 다른 시간과 어떻게 비교됩니까?

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

적어도 내 컴퓨터에서는 pdox의 답변이 @moonshadow moonshadow의 답변보다 약간 빠르므로 pdox가 전체 HP (Intel 랩톱에서) 가장 빠릅니다.


3

루비에서 :

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

JavaVM의 JRuby에서 실행할 수 있습니다. ;-)


3

그는 아마도 비트 비교 연산자 (일반적으로 복잡하지는 않지만 부울로 비트 연산자를 사용하는 것이 매우 이상합니다) 또는 int로 변환하고 합산하는 것과 같은 매우 둥근 것 같은 복잡한 것을 찾지 않을 것입니다.

이것을 해결하는 가장 직접적이고 자연스러운 방법은 다음과 같은 표현입니다.

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

원하는 경우 함수에 넣으십시오. 그러나 그렇게 복잡하지는 않습니다. 이 솔루션은 논리적으로 간결하고 효율적입니다.


3

C에서 :

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

실제로,이 대답은 잘못되었습니다 . 정확히 2 개가 아닌 2 개 이상의 실제 부울 이 필요하기 때문에> = 2 여야합니다 .
Paul Wagland

@Paul Wagland : 감사합니다.
Matt Joiner

@ergosys : 내가 두 번 대답?
Matt Joiner
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.