4

Let's say I have 4 variables

bool value1 = false;
bool value2 = false;
bool value3 = true;
bool value4 = false;

and they all don't have the same value (all are true || all are false)

I have found 2 approaches, anyway none of them looks easy to understand.

bool areDifferent = !(value1 == value2 == value3 == value4);

and

bool areDifferent = new[] { value1, value2, value3, value4 }.Distinct().Count() > 1;

Question: Is there a other approach, which is better in terms of readability / understandability?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Impostor
  • 2,080
  • 22
  • 43
  • 4
    Both lines look pretty readable and easy to understand to me. This seems like an entirely subjective question and probably not a great one for StackOverflow. You might try to take a moment to understand what the code is doing there if you don't get what they are doing. – tnw Jan 14 '21 at 15:32
  • 1
    They both looks easy to understand. As alternative you can have `bool areSame` and use `!areSame` to check if there is a difference. – Sinatr Jan 14 '21 at 15:32
  • 1
    Does this answer your question? [Check if all items are the same in a List](https://stackoverflow.com/questions/5307172/check-if-all-items-are-the-same-in-a-list) –  Jan 14 '21 at 15:36
  • 1
    @Impostor any imperative code is bad in terms of readability/understandability. Also, your first approach is incorrect. Try with `true, false, true, false` to see what is wrong – Sergey Berezovskiy Feb 11 '21 at 20:45
  • 1
    `value1 == value2 == value3 == value4` that's not right though. You're comparing the result of the comparisons, not the values themselves. – Jeremy Lakeman Feb 12 '21 at 02:03
  • Your first approach is wrong. Your second approach is good enough. – Reza Aghaei Feb 14 '21 at 16:49

8 Answers8

10

For readability and understanding, I would swap the logic. When you check if values are different it's not clear - all values should be different (consider integer values 1, 2, 3), or values could be equal, but there is at least one different value (1, 2, 1)? When you check if all values are equal it's always clear.

And I would extract this logic to the nicely named method (you can even make it generic if you want):

public static bool AllEqual(params bool[] values)
{
    if (values.Length == 0)
       return true;

    var first = values[0];
    for (int i = 1; i < values.Length; i++)
        if (values[i] != first)
            return false;

    return true;
}

And usage

var notAllEqual = !AllEqual(value1, value2, value3, value4);

With declarative approach your code describes what you are doing instead of telling how and leaving the reader on its own to understand what.


Update: If you always deal with four boolean values, the simplest way to check if they are not all equal is

(value1 ^ value2) || (value2 ^ value3) || (value3 ^ value4)

But in terms of readability, any imperative approach is worse than declarative

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • `!=` easier to understand than `^`. Another option is `!(value1 == value2 && value2 == value3 && value3 == value4)` – Charlieface Feb 15 '21 at 00:35
3

You can combine the bits and check

int value = (value1 ? 8 : 0) |
            (value2 ? 4 : 0) |
            (value3 ? 2 : 0) |
            (value4 ? 1 : 0);
return value != 0 && value != 15;
phuclv
  • 37,963
  • 15
  • 156
  • 475
  • Nice one. A bit hacky and limited, but still... You've inspired me to [this one](https://stackoverflow.com/a/66190392/10958092). – CSDev Feb 13 '21 at 22:08
3

Maybe Linq is declarative enough?

var values = new[] { false, false, true, false };
bool notAllEqual = values.Any(x => x != values.First());

Alternatively:

var values = new[] { false, false, true, false };
bool allEqual = values.All(x => x == values.First());
if (!allEqual)
{
     // They are different
}
Ulf Kristiansen
  • 1,571
  • 3
  • 22
  • 34
1

You said you want to check if your elements not

all are true || all are false

Given a list var values = new List<bool> { value1, value2, value3, value4 }; of those elements, the closest representation in code would be:

var areDifferent = !(values.All(v => v == true) || values.All(v => v == false));

In terms of readability though, I would prefer:

var areEqual = values.All(v => v == true) || values.All(v => v == false);

and later check:

 if (!areEqual)
 {
     // Do something
 }

But that's just personal preference.

Kai Hartmann
  • 3,106
  • 1
  • 31
  • 45
1

This seems to me a code smell, you might need to refactor the code instead of searching of a better way to display the booleans.

Without providing the actual code, you'll always get assumptions and not answers.

Anyhow, regarding to your specific question, you can create a public static class and use it as results tester to validate all kind of results through out your code. This way, you can reuse it, and also would be more readable.

for instance :

public static class Validate
{
    public static bool AreEqual(params bool[] values) => AreTrue(values) || AreFalse(values);
    
    public static bool AreTrue(params bool[] values) => values.All(x => x == true);
    
    public static bool AreFalse(params bool[] values) => values.All(x => x == false);
}

then use it like this :

bool value1 = false;
bool value2 = false;
bool value3 = true;
bool value4 = false;

if(Validate.AreEqual(value1 , value2 , value3 , value4))
{
    // do something
}
iSR5
  • 3,274
  • 2
  • 14
  • 13
  • This wont work for false values....if all the values are false, your method will return false, but the values are equal. – Marmellad Feb 14 '21 at 22:25
0

Although personally, I prefer your first approach, the following works as well.

bool value1 = false;
bool value2 = false;
bool value3 = true;
bool value4 = false;

var values = new[] { value1, value2, value3, value4 };

bool areDifferent = values.Any(v => v) && values.Any(v => !v);
phuclv
  • 37,963
  • 15
  • 156
  • 475
Sajjad Mortazavi
  • 190
  • 2
  • 12
0

@phuclv's approach made generic:

static bool AreDifferent(params bool[] values)
{
    var tmp = values.Select((value, index) => value ? 1 << index : 0).Aggregate((i, j) => i | j);
    return tmp != 0 && tmp != (1 << values.Length) - 1;
}
CSDev
  • 3,177
  • 6
  • 19
  • 37
-1

For understanding purpose, we can create a method and use if blocks.

public bool areDifferent(bool value1, bool value2, bool value3, bool value4)
{
    if(value1 == value2)
        if(value2 == value3)
            if(value3 == value4)
                return false;
                    
    return true;
}