Logic để kiểm tra 3 trên 4 là True


163

Tôi muốn trả về Truekhi và chỉ khi 3 trong số 4 giá trị boolean là đúng.

Gần nhất tôi đã nhận được là (x ^ y) ^ (a ^ b):

Tôi nên làm gì?


10
Hmm, cách duy nhất tôi có thể nghĩ ra với công thức toán học là sử dụng số đếm. Câu hỏi hay! :)
Tôi là Cavic

10
Ý tưởng của bạn không tệ, nhưng bạn phải lấy các phủ định: not a ^ not b ^ not c ^ not dlà đúng khi chính xác một trong các giá trị phủ định là đúng. Điều này có nghĩa, từ các giá trị ban đầu, chính xác là một giá trị sai.
Ingo

23
Vấn đề thực sự của bạn đằng sau chi tiết này là gì?
Sói

5
@Ingo không a ^ không b ^ không c ^ không d trả về true trong đó chỉ có một là sai VÀ trong đó 3 là sai.
NameSpace

9
Các giải pháp không đếm rõ ràng là (!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d).
Jason C

Câu trả lời:


248

Tôi đề nghị viết mã theo cách chỉ ra ý của bạn. Nếu bạn muốn 3 giá trị là đúng, đối với tôi, giá trị 3 xuất hiện ở đâu đó là điều tự nhiên.

Ví dụ C++: trong :

if ((int)a + (int)b + (int)c + (int)d == 3)
    ...

Điều này được xác định rõ trong C++: standard (§4.7/4)chỉ ra rằng chuyển đổi boolđể intcung cấp các giá trị mong đợi 0 hoặc 1.

Trong Java và C #, bạn có thể sử dụng cấu trúc sau:

if ((a?1:0) + (b?1:0) + (c?1:0) + (d?1:0) == 3)
    ...

23
Đây là một câu trả lời tốt. Điều này trông giống như một trường hợp của điều X / Y đó. "Anh ấy muốn làm X bằng Y, nhưng không biết làm Y. Thay vì hỏi X, anh ấy hỏi Y." Trừ khi anh ta đang thiết kế một mạch logic hoặc một cái gì đó tương tự (và sau đó anh ta sẽ ở sai trang web), cách tốt nhất để làm điều này là theo cách có thể đọc được .
NothingsImpossible

2
@NothingsImpossible Không có gì XY về câu hỏi. Đó là một câu hỏi rõ ràng và thẳng thắn về việc giải quyết một vấn đề khá phổ biến trong lập trình. Chữ Y không liên quan.
Ярослав Рахматуллин

Cảm ơn! Đây thực sự là những gì tôi muốn làm, nhưng ý tưởng của tôi vụng về đến mức tôi đã đạt được logic boolean.
Simon Kuang

3
if (!!a + !!b + !!c + !!d == 3)dễ viết hơn, mặc dù tôi không biết liệu trình biên dịch có tối ưu hóa điều này hay không
phuclv

2
Lưu ý rằng trong c ++, việc truyền từ bool sang int là không cần thiết.
PlasmaHH

90

# 1: Sử dụng phân nhánh ?: 3 hoặc 4 thao tác

A ^ B ? C & D : ( C ^ D ) & A

# 2 Không phân nhánh, 7 hoạt động

(A ^ B ^ C ^ D) & ((A & B) | (C & D))

Quay lại khi tôi sử dụng để cấu hình mọi thứ, tôi thấy các giải pháp không phân nhánh hoạt động nhanh hơn một chút vì CPU có thể dự đoán đường dẫn mã tốt hơn và thực hiện nhiều hoạt động hơn song song. Có khoảng 50% công việc ít hơn trong tuyên bố phân nhánh ở đây mặc dù.


18
+1 - trong khi các câu trả lời khác tốt hơn cho hầu hết các ngôn ngữ lập trình, thì số 2 của bạn là câu trả lời tốt nhất trong logic boolean thuần túy.
Brilliand


68

Nếu đây là Python, tôi sẽ viết

if [a, b, c, d].count(True) == 3:

Hoặc là

if [a, b, c, d].count(False) == 1:

Hoặc là

if [a, b, c, d].count(False) == True:
# In Python True == 1 and False == 0

Hoặc là

print [a, b, c, d].count(0) == 1

Hoặc là

print [a, b, c, d].count(1) == 3

Hoặc là

if a + b + c + d == 3:

Hoặc là

if sum([a, b, c, d]) == 3:

Tất cả đều hoạt động, vì Booleans là các lớp con của số nguyên trong Python.

if len(filter(bool, [a, b, c, d])) == 3:

Hoặc, lấy cảm hứng từ thủ thuật gọn gàng này ,

data = iter([a, b, c, d])
if not all(data) and all(data):

17
+1 Điều này giải quyết vấn đề bằng cách dịch chính xác nó sang Python.
Sói

Điều này hơi nguy hiểm vì mọi người có thể trả về bất kỳ số nguyên khác không trong bối cảnh boolean trong python. Thủ thuật C cũ cũng hoạt động trong python : a=5;not not a == 1. Nhược điểm của việc không có một loại boolean thực sự.
Voo

@Voo Chúng tôi cũng có bool:)
thefourtheye

@thefourtheye À đúng rồi, đẹp hơn nhiều so với thủ thuật / hack phủ định kép.
Voo

1
Hoặc ... hoặc .... hoặc .... Nên có một-- và tốt nhất là chỉ có một cách rõ ràng để làm điều đó. : - / :-)
rz.

53

Dài nhưng rất đơn giản, (không đồng ý) dạng bình thường:

 (~a & b & c & d) | (a & ~b & c & d) | (a & b & ~c & d) | (a & b & c & ~d)

Nó có thể được đơn giản hóa nhưng điều đó đòi hỏi nhiều suy nghĩ hơn: P


2
@Ben chỉ cung cấp cho bạn các hình thức bình thường khác nhau, cái này đã có trong (DNF).
Đi xe đạp

8
Thế còn (a & b & (c ^ d)) | ((a ^ b) & c & d)?
dùng253751

2
Vâng, @immibis, theo Wolfram Alpha, DNF của nó là công thức tôi đã viết để nó có cùng chức năng boolean.
Gastón Bengolea

2
+1 vì tôi nghĩ ai đó đang đọc mã sẽ hiểu những gì đang được thử nhanh hơn so với các câu trả lời khác.
Boluc Papuccuoglu


22

Nếu bạn muốn sử dụng logic này trong ngôn ngữ lập trình, đề xuất của tôi là

bool test(bool a, bool b, bool c, bool d){
    int n1 = a ? 1 : 0;
    int n2 = b ? 1 : 0;
    int n3 = c ? 1 : 0;
    int n4 = d ? 1 : 0;

    return n1 + n2 + n3 + n4 == 3;
}

Hoặc nếu bạn muốn, bạn có thể đặt tất cả những thứ này trong một dòng duy nhất:

return (a ? 1 : 0) + (b ? 1 : 0) + (C ? 1 : 0) + (d ? 1 : 0) == 3;

Ngoài ra, bạn có thể khái quát vấn đề này để n of m :

bool test(bool *values, int n, int m){
    int sum = 0;
    for(int i = 0; i < m; i += 1){
        sum += values[i] ? 1 : 0;
    }
    return sum == n;
}

12
Đánh tôi với nó Dễ đọc hơn hẳn sự thông minh, mọi lúc. +1
MikeTheLiar

20

Câu trả lời này phụ thuộc vào hệ thống biểu diễn, nhưng nếu 0 là giá trị duy nhất được hiểu là sai và not(false)luôn trả về cùng một giá trị số, thì not(a) + not(b) + not(c) + not(d) = not(0)nên thực hiện thủ thuật.


18

Hãy nhớ rằng SO nếu cho câu hỏi lập trình, thay vì chỉ là vấn đề logic, câu trả lời rõ ràng phụ thuộc vào sự lựa chọn ngôn ngữ lập trình. Một số ngôn ngữ hỗ trợ các tính năng không phổ biến với những người khác.

Ví dụ: trong C ++, bạn có thể kiểm tra các điều kiện của mình bằng:

(a + b + c + d) == 3

Đây phải là cách nhanh nhất để thực hiện kiểm tra các ngôn ngữ hỗ trợ chuyển đổi tự động (cấp thấp) từ loại boolean sang số nguyên. Nhưng một lần nữa, không có câu trả lời chung cho vấn đề đó.


2
Đây là câu trả lời tôi sẽ đăng. Một điều cần thêm vào, tùy thuộc vào ngôn ngữ lập trình được sử dụng, câu trả lời bạn muốn sẽ là -3. Trong VB, True = -1.
Tom Collins


11
((a xor b) xor (c xor d)) and ((a or b) and (c or d))

Biểu thức nắm tay tìm kiếm 1 hoặc 3 truetrong số 4. Biểu thức thứ hai loại bỏ 0 hoặc 1 (và đôi khi 2) truetrong số 4.


11

Java 8, lọc ra các giá trị sai và đếm các giá trị đúng còn lại:

public static long count(Boolean... values) {
    return Arrays.stream(values).filter(t -> t).count();
}

Sau đó, bạn có thể sử dụng nó như sau:

if (3 == count(a, b, c, d)) {
    System.out.println("There... are... THREE... lights!");
}

Dễ dàng khái quát để kiểm tra ncác mmặt hàng là đúng sự thật.


11

Để kiểm tra ít nhất ntất cả Booleanlà đúng, (n phải nhỏ hơn hoặc bằng tổng số Boolean: p)

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) >= n) {
    // do the rest
}

Chỉnh sửa : Sau khi bình luận của @ Cruncher

Để kiểm tra 3 booleantrên 4

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) == 3) {
    // do the rest
}

Một số khác:

((c & d) & (a ^ b)) | ((a & b) & (c ^ d))( Chi tiết )


OP muốn chính xác n, không ít nhất n. Nhưng đó là một thay đổi dễ dàng từ giải pháp này
Cruncher

2
@Wolf câu hỏi đó thuộc về StackUnderflow.com: p
Không phải là lỗi

10

Đây là một cách bạn có thể giải quyết nó trong C # với LINQ:

bool threeTrue = new[] { a, b, x, y }.Count(x => x) == 3;

10

Đó là hàm Boolean đối xứng S₃(4) . Hàm Boolean đối xứng là hàm boolean chỉ phụ thuộc vào số lượng đầu vào được đặt, nhưng không phụ thuộc vào đầu vào nào. Knuth đề cập đến các chức năng của loại này trong phần 7.1.2 trong Tập 4 của Nghệ thuật lập trình máy tính.

S₃(4) có thể được tính toán với 7 thao tác như sau:

(x && y && (a || b)) ^ ((x || y) && a && b)

Knuth cho thấy điều này là tối ưu, có nghĩa là bạn không thể thực hiện việc này trong ít hơn 7 thao tác bằng cách sử dụng các toán tử thông thường: &&, || , ^, <,> .

Tuy nhiên, nếu bạn muốn sử dụng ngôn ngữ này trong ngôn ngữ sử dụng 1đúng và 0sai, bạn cũng có thể dễ dàng sử dụng bổ sung:

x + y + a + b == 3

mà làm cho ý định của bạn khá rõ ràng.


9
(a && b && (c xor d)) || (c && d && (a xor b))

Từ quan điểm logic thuần túy, đây là những gì tôi nghĩ ra.

Theo nguyên tắc lỗ chim bồ câu, nếu chính xác 3 là đúng, thì a và b là đúng, hoặc c và d là đúng. Sau đó, nó chỉ là vấn đề anding từng trường hợp với chính xác một trong 2 trường hợp còn lại.

Bảng chân lý Wolfram


Điều này tương đương với giải pháp thứ hai của NameSpace.
Brilliand

@Brilliand Có vẻ khác với tôi. Các xors của anh ta cùng nhau để có được tất cả 3 hoặc 1, sau đó loại trừ những người có 1 bằng cách yêu cầu ít nhất một từ 2 nhóm riêng biệt. (tóm tắt là 1 hoặc 3 và ít nhất 2). Của tôi yêu cầu cả hai từ một trong các nhóm riêng biệt, và sau đó chính xác một từ nhóm khác.
Cruncher

Nếu bạn có nghĩa tương đương theo nghĩa đó mine <=> histhì tôi không biết phải nói gì vì điều này sẽ được mong đợi.
Cruncher

Tôi đoán tôi có nghĩa là câu trả lời này tốt theo cách chính xác giống như cách giải pháp thứ hai của NameSpace là tốt, mà không cần thêm bất cứ điều gì mới mà câu trả lời (trước đó) của NameSpace không bao gồm. Vâng, tôi sẽ upvote nào.
Brilliand

8

Nếu bạn sử dụng một công cụ trực quan logic như Karnaugh Maps, bạn sẽ thấy rằng đây là một vấn đề mà bạn không thể tránh được một thuật ngữ logic đầy đủ nếu bạn muốn viết nó trong một dòng if (...). Lopina đã cho thấy nó rồi, không thể viết nó đơn giản hơn. Bạn có thể tính ra một chút, nhưng nó sẽ khó đọc cho bạn VÀ cho máy.

Giải pháp đếm không phải là xấu và chúng cho thấy những gì bạn thực sự sau. Làm thế nào bạn làm việc đếm hiệu quả phụ thuộc vào ngôn ngữ lập trình của bạn. Các giải pháp mảng với Python oder LinQ rất đẹp để xem xét, nhưng hãy cẩn thận, đây là SLOW. Wolf's (a + b + x + y) == 3 sẽ hoạt động tốt và nhanh, nhưng chỉ khi ngôn ngữ của bạn bằng "true" với 1. Nếu "true" được biểu thị bằng -1, bạn sẽ phải kiểm tra -3: )

Nếu ngôn ngữ của bạn sử dụng booleans thực sự, bạn có thể thử lập trình nó một cách rõ ràng (tôi sử dụng! = Như thử nghiệm XOR):

if (a)
{
    if (b)
        return (x != y);    // a,b=true, so either x or y must be true
    else
        return (x && y);     // a=true, b=false, so x AND y must be true
}
else
{
    if (b)
        return (x && y);    // a=false, b=true, so x and y must be true
    else
        return false;       // a,b false, can't get 3 of 4
}

"x! = y" chỉ hoạt động nếu x, y thuộc loại boolean. Nếu chúng là một số loại khác trong đó 0 là sai và mọi thứ khác là đúng, điều này có thể thất bại. Sau đó sử dụng XOR boolean hoặc ((bool) x! = (Bool) y) hoặc viết "if (x) return (y == false) other return (y == true);", nhiều hơn một chút làm việc cho máy tính.

Nếu ngôn ngữ lập trình của bạn cung cấp toán tử ternary ?:, Bạn có thể rút ngắn nó thành

if (a)
    return b ? (x != y) : (x && y);
else
    return b ? (x && y) : false;

mà giữ một chút khả năng đọc, hoặc cắt nó mạnh mẽ để

return a ? (b ? (x != y) : (x && y)) : (b ? (x && y) : false);

Mã này thực hiện chính xác ba bài kiểm tra logic (trạng thái a, trạng thái b, so sánh x và y) và phải nhanh hơn hầu hết các câu trả lời khác ở đây. Nhưng bạn cần bình luận, hoặc bạn sẽ không hiểu nó sau 3 tháng :)


8

Có rất nhiều câu trả lời hay ở đây; đây là một công thức thay thế mà chưa có ai khác đăng:

 a ? (b ? (c ^ d) : (c && d)) : (b && c && d)

Cảm ơn câu trả lời của bạn, nhưng bạn có thể vui lòng thêm một số bình luận về cách thức hoạt động không? Cảm ơn.
Deanna

(Xin lỗi vì đã chọn bạn, tôi đã nhận nó dưới dạng kiểm toán đánh giá. Ít nhất tôi đã vượt qua .. :))
Deanna

7

Tương tự như câu trả lời đầu tiên, nhưng thuần Java:

int t(boolean b) {
    return (b) ? 1 : 0;
}

if (t(x) + t(y) + t(a) + t(b) == 3) return true;
return false;

Tôi thích tính chúng là số nguyên vì nó làm cho mã dễ đọc hơn.


7

Trong Python , để xem có bao nhiêu phần tử lặp lại là True, hãy sử dụng sum(nó khá đơn giản):

Thiết lập

import itertools

arrays = list(itertools.product(*[[True, False]]*4))

Kiểm tra thực tế

for array in arrays:
    print(array, sum(array)==3)

Đầu ra

(True, True, True, True) False
(True, True, True, False) True
(True, True, False, True) True
(True, True, False, False) False
(True, False, True, True) True
(True, False, True, False) False
(True, False, False, True) False
(True, False, False, False) False
(False, True, True, True) True
(False, True, True, False) False
(False, True, False, True) False
(False, True, False, False) False
(False, False, True, True) False
(False, False, True, False) False
(False, False, False, True) False
(False, False, False, False) False

5

Nếu bạn theo đuổi giải pháp trên giấy (không lập trình), thì thuật toán K-maps và Quine-McCluskey là những gì bạn đang theo đuổi, chúng giúp bạn giảm thiểu chức năng boolean của bạn.

Trong trường hợp của bạn, kết quả là

y = (x̄3 ^ x2 ^ x1 ^ x0) ∨ (x3 ^ x̄2 ^ x1 ^ x0) ∨ (x3 ^ x2 ^ x̄1 ^ x0) ∨ (x3 ^ x2 ^ x1 ^ x̄0)

Nếu bạn muốn thực hiện việc này theo chương trình, số lượng biến không cố định và "ngưỡng" tùy chỉnh, thì chỉ cần lặp qua một danh sách các giá trị boolean và đếm số lần xuất hiện của "true" là khá đơn giản và dễ hiểu.


1
Thanh trên có nghĩa là gì? Tôi nhận thấy nó di chuyển xuống danh sách.
NameSpace

3
@NameSpace Đây là một trong những IMO có quá nhiều ký hiệu mà mọi người sử dụng để thể hiện "không".

5

Tôi muốn trả về true khi và chỉ khi 3 trong 4 giá trị boolean là true.

Cho 4 giá trị boolean, a, b, x, y, tác vụ này chuyển thành câu lệnh C sau:

return (a+b+x+y) == 3;

1
Cái bẫy đẹp. Giả định này truebằng 1. Điều này không đúng (không có ý định chơi chữ) trong tất cả các ngôn ngữ / trường hợp. blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspx
JensG

@JensG Bạn nói đúng: Tôi đưa ra giả định này rõ ràng. Thx :)
Sói

4
((a^b)^(x^y))&((a|b)&(x|y))

là những gì bạn muốn. Về cơ bản tôi đã lấy mã của bạn và thêm kiểm tra nếu thực sự 3 là đúng và không phải 3 là sai.


4

Một câu hỏi lập trình mà không có câu trả lời liên quan đến đệ quy? Không thể hiểu được!

Có đủ câu trả lời "chính xác 3 trong 4 câu hỏi", nhưng đây là phiên bản tổng quát (Java) cho "chính xác m trong số các câu hỏi" (nếu không thì đệ quy không thực sự có giá trị) chỉ vì bạn có thể:

public static boolean containsTrues(boolean[] someBooleans,
    int anIndex, int truesExpected, int truesFoundSoFar) {
  if (anIndex >= someBooleans.length) {
    return truesExpected == truesFoundSoFar; // reached end
  }
  int falsesExpected = someBooleans.length - truesExpected;
  boolean currentBoolean = someBooleans[anIndex];
  int truesFound = truesFoundSoFar + (currentBoolean ? 1 : 0);
  if (truesFound > truesExpected) {
    return false;
  }
  if (anIndex - truesFound > falsesExpected) {
    return false; // too many falses
  }
  return containsTrues(someBooleans, anIndex + 1, truesExpected,
      truesFound);
}

Điều này có thể được gọi với một cái gì đó như:

 boolean[] booleans = { true, false, true, true, false, true, true, false };
 containsTrues(booleans, 0, 5, 0);

sẽ trả về true(vì 5 trong số 8 giá trị là đúng, như mong đợi). Không hoàn toàn hài lòng với các từ "trues" và "falses", nhưng không thể nghĩ ra một cái tên tốt hơn ngay bây giờ .... Lưu ý rằng đệ quy dừng lại khi tìm thấy quá nhiều true hoặc quá nhiều falsegiá trị.


@ FélixSaparelli: Không chắc chắn "sự thật" áp dụng ở đây ... có vẻ như bạn đang hạnh phúc chỉ với một true. Có lẽ một cái gì đó như containsNumberOfTrueValues(). Như một bên: Đặt tên của Smalltalk sẽ phù hợp hơn nhiều cho việc này, mặc dù : doesArray: someBooleans startingAt: anIndex containNumberOfTrueValues: anExpectedNumber foundSofar: aNumberFoundSoFar. Có lẽ quá dài đối với thị hiếu của một số nhà phát triển Java, nhưng Smalltalker không bao giờ sợ đặt tên đúng ;-)
Amos M. Carpenter

Điều đó chủ yếu là hài hước. Và containsTruthcó nghĩa là "chứa một số lượng sự thật không được tiết lộ", theo nghĩa đen, vì vậy tôi tin rằng nó khá ổn.
Félix Saparelli

3

Vì khả năng đọc là một mối quan tâm lớn, bạn có thể sử dụng lệnh gọi mô tả (gói bất kỳ triển khai được đề xuất nào). Nếu việc tính toán này cần được thực hiện ở nhiều nơi, một cuộc gọi hàm là cách tốt nhất để đạt được việc sử dụng lại và làm cho nó rõ ràng chính xác những gì bạn đang làm.

bool exactly_three_true_from(bool cond1, bool cond2, bool cond3, bool cond4)
{
    //...
}

3

Trong PHP, làm cho nó năng động hơn (chỉ trong trường hợp bạn thay đổi số lượng điều kiện, v.v.):

$min = 6;
$total = 10;

// create our boolean array values
$arr = array_map(function($a){return mt_rand(0,1)>0;},range(1,$total));

// the 'check'
$arrbools = array_map(function($a){return (int)$a;},$arr);
$conditionMet = array_sum($arrbools)>=$min;

echo $conditionMet ? "Passed" : "Failed";

2
(((a AND b) OR (x AND y)) AND ((a XOR b) OR (x XOR y)))

Mặc dù tôi có thể chỉ ra rằng đây là một giải pháp tốt, nhưng câu trả lời của Sam Hocevar rất dễ viết và hiểu sau này. Trong cuốn sách của tôi mà làm cho nó tốt hơn.


1

Đây là một số mã c # tôi vừa viết vì bạn đã truyền cảm hứng cho tôi:

Nó cần bất kỳ số lượng đối số và sẽ cho bạn biết nếu n trong số chúng là đúng.

    static bool boolTester(int n, params bool[] values)
    {
        int sum = 0;           

        for (int i = 0; i < values.Length; i++)
        {
            if (values[i] == true)
            {
                sum += 1;
            }                
        }
        if( sum == n)
        {
            return true;
        }            
        return false;                
    }

và bạn gọi nó như vậy:

        bool a = true;
        bool b = true;
        bool c = true;
        bool d = false;            

        bool test = false;
        test = boolTester(3, a, b, c, d);

Vì vậy, bây giờ bạn có thể kiểm tra 7/9 hoặc 15/100 như bạn muốn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.