Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

count of objects in 2 dimensional NSArray

I have an NSArray inside an NSArray so:

@[
    @[ @1, @2, @3 ],
    @[ @7, @6 ]
 ]

How can I use the method valueForKeyPath: to get the number of items in each array, so this:

@[ @3, @2 ]

I have tried [array valueForKeyPath:@"@count"] but that provides the same answer as [array count] (so 2) as does [array valueForKeyPath:@"count"].

like image 793
Jonathan. Avatar asked Dec 25 '22 18:12

Jonathan.


1 Answers

Use the @unionOfObjects and @count KVC collection operators in conjunction:

NSArray *counts = [array valueForKeyPath:@"@unionOfObjects.@count"];

Logging counts in this case yields:

counts = (
    3,
    2
)

Calling valueForKey: and its variants on an NSArray instance typically is used to return an array formed from the result of calling valueForKey: on each element in the receiver. So, [array valueForKey:@"count"] won't return the value returned by -[NSArray count] but rather will call valueForKey:@"count" on each of its elements. Arrays nested inside others won't behave any differently, so we can't use @"count" as our key path directly as it will try to delegate that calculation to each of its elements. Using @"@count" as the key path won't work, either, because it operates on the key to its left, which is implied to be the receiver of the valueForKeyPath: method when no other key path is specified.

What we need is a way to specify that the @count operator should count not the enclosing array but the elements thereof. Using the @unionOfObjects collection operator in our key path accomplishes this. If we have a key path such as:

@unionOfObjects.$COLLECTION.$REST_OF_KEYPATH

Then the result returned will be the array formed by the results of sending each element of $COLLECTION a valueForKeyPath: message with $REST_OF_KEYPATH as the argument. One last fact - when the receiver of a valueForKeyPath: message is itself a collection, then $COLLECTION can be specified in the key path with the string self.

Accordingly, our key path should look like:

@"@unionOfObjects.self.@count"

This specifies that an array will be returned with each element being the result of sending -valueForKeyPath:@"@count" to each element in the receiver. Finally, and I'm not sure about the advisability of this, but it seems that self can be removed from the keypath entirely so long as the @unionOfObjects operator is not the only component of the key path. In this case, it substitutes for the @unionOfObjects.$COLLECTION component of the key path.

like image 91
Carl Veazey Avatar answered Dec 28 '22 07:12

Carl Veazey