6

I have a mutable array of Boolean values and I want to check to see if ANY of the values are YES.

At present I am creating another array alongside this one which is always ALL False like so;

 [MyArray addObject:[NSNumber numberWithBool:switchInput]];
 [MyAllNoArray addObject:[NSNumber numberWithBool:NO]];

The user does some bits and the some of the objects in MyArray may become YES, I then use the below to see if ANY are true or not.

if([MyArray isEqualToArray:MyAllNoArray])

I am just wondering if there is a better way (this way seems wasteful)?

I have thought about a counter, each time one of the objects changes the counter goes up or down (depending on changing to YES or NO), if the counter is 0 then so is the array. But I am just thinking there may be a better way within an IF statement that I am missing.

Hot Licks
  • 44,830
  • 15
  • 88
  • 146
Recycled Steel
  • 2,204
  • 3
  • 27
  • 35
  • The simple loop is faster and conceptually simpler. – Hot Licks Sep 04 '13 at 16:49
  • I like the counter idea. Since it's OO, you can encapsulate that behavior. Normally I'd say don't pre-optimize, but if you know the array might be large, seems like a good case. – Marcus Adams Sep 04 '13 at 17:06

6 Answers6

11

I think a simpler solution would be this:

NSArray *bools = @[@(NO),@(NO), @(YES)];
    if ([bools containsObject:@(YES)]) {
        // do your magic here
    }

Loops and blocks would be an overkill if you just need to check for presence.

  • 2
    Nice! - Just two remarks: 1) `containsObject:` most probably uses a loop internally, so this method should be equally fast as an explicit loop. 2) You can write `@YES` (NSNumber literal) instead of `@(YES)` (boxed expression). The result is the same. – Martin R Sep 04 '13 at 17:46
  • I think all in all whichever method is used some kind of internal/external loop will happen. I ticked this one as it was the first with this answer and this answer reads really well (easy on the eye). – Recycled Steel Sep 04 '13 at 19:32
  • @MartinR Yep this works really well, not sure I understand the @(YES), is this modern C++ for [NSNumber numberWithBool:YES]? – Recycled Steel Sep 04 '13 at 19:37
  • @RecycledSteel: That is a (modern) Objective-C "Boxed Expressions". See http://clang.llvm.org/docs/ObjectiveCLiterals.html. – Martin R Sep 04 '13 at 19:40
  • This is great. Relatively new to Objective C and the language seems so verbose, so very thankful for anytime I can make it less verbose! – prototypical Feb 28 '14 at 23:09
1
NSArray *myArray;

__block bool hasTrue = NO;
[myArray enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
    if (num.boolValue) {
        hasTrue = YES;
        *stop = YES;
    }
}];

if (hasTrue)
    NSLog(@"there is a true value in myArray.");
else
    NSLog(@"there is not true value in myArray.");

Or turn it into a method:

- (BOOL)doesMyArrayHaveTrue {
    NSArray *myArray;

    __block bool hasTrue = NO;
    [myArray enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
        if (num.boolValue) {
            hasTrue = YES;
            *stop = YES;
        }
    }];

    return hasTrue;
}

Or...I haven't tried this yet but I think it should work:

NSNumber * max = [myArray valueForKeyPath:@"@max.self"];
if (max.boolValue)
    NSLog(@"there is a true values.");
else
    NSLog(@"there is not a true value.");
random
  • 8,428
  • 12
  • 46
  • 81
1

The easiest way is to use containsObject:@(YES).

Explanation

If you check the NSArray documentation it says

containsObject: Returns a Boolean value that indicates whether a given object is present in the array.

  • (BOOL)containsObject:(id)anObject

Discussion

This method determines whether anObject is present in the array by sending an isEqual: message to each of the array’s objects (and passing anObject as the parameter to each isEqual: message).

So containsObject:@(YES) should do the trick

rr1g0
  • 363
  • 4
  • 13
0

Pretty much the same answer as random, but without blocks.

bool allFalse = true;
for(NSNumber *number in MyArray)
{
    if([number boolValue])
    {
        allFalse = false;
        break;
    }
}

if(!allFalse)
{
    ...
}
Putz1103
  • 6,081
  • 1
  • 14
  • 24
  • Really, I Fast Enumeration is quicker than an isEqualToArray? I suppose the net total is (after I mess about with the second array). – Recycled Steel Sep 04 '13 at 16:57
  • 1
    @RecycledSteel -- What do you suppose has to go on inside isEqualToArray? There is a mythical belief that using a "high level" function is somehow faster than using simple loops, et al. That is occasionally true, but just as often not. – Hot Licks Sep 04 '13 at 16:59
0
NSNumber* yesBool = [NSNumber numberWithBool:YES];
BOOL foundYes = NO;
for (NSNumber* num in MyArray) {
    if ([num isEqualToNumber:yesBool) {
        foundYes = YES;
        break;
    }
}

You can't do much (*) better than that for a test without some sort of "score", though your counter scheme is no doubt better, should you choose to "keep score".

(*) It's debatable whether using isEqualToNumber is more or less efficient than simply testing boolValue.

Hot Licks
  • 44,830
  • 15
  • 88
  • 146
0

Many good answers here, and @Arcanfel and @rr1g0's suggestion of simply using containsObject: is really elegant and simple.

The many esteemed colleagues who have answered the thread have left out an important option, though - a predicate-based solution. So here goes, in the interest of completeness:

NSArray *data = @[@(NO), @(YES), @(NO)];

NSPredicate *hasYesPred = [NSPredicate predicateWithFormat: @"SUBQUERY(SELF, $s, $s == %@).@count > 0", @(YES)];

BOOL hasYes = [hasYesPred evaluateWithObject: data];

The idea here is that the subquery constructs an array of objects that are equal to @(YES), then we take the count of that, and if it is positive, we know that there is at least one true boolean value in the array.

This approach obviously can be extended to other types of numbers - to determine if there is at least one negative number in an array, for instance.

Monolo
  • 17,926
  • 16
  • 63
  • 102
  • I agree it is good to know all options and thanks for filling the gap. I think I will go for the containsObject option though as it reads better than any other. – Recycled Steel Sep 04 '13 at 19:34