AAV
AAV

Reputation: 3803

How to convert valueForKeyPath in swift

My old function in objective c is

+ (NSUInteger)getNumberOfDistinctUsers:(NSArray *)users {
NSArray* usersAfterPredicate = [users valueForKeyPath:@"@distinctUnionOfObjects.userName"];
return [usersAfterPredicate count]; }

How do I convert this in swift, I was trying to something like this but its crashing "Could not cast value of type 'Swift.Array'to 'Swift.AnyObject'"

static func getNumberOfDistinctUsers(users: [ICEPKReferenceDataUser]) -> Int {

    var retval : Int = 0
    if let usersAfterPredicate = (users as! AnyObject).valueForKeyPath("@distinctUnionOfObjects.userName") {
        retval = usersAfterPredicate.count
    }
    return retval
}

Can I solve this problem using filter, map or Reduce? I am just trying to find out distint users in users array using the property username.

Edit* brute force way

    static func getNumberOfDistinctUsers(users: [ICEPKReferenceDataUser]) -> Int {

    var retvalSet : Set<String> = []
    for user in users {
        retvalSet.insert(user.userName)
    }
    return retvalSet.count
}

Upvotes: 3

Views: 2921

Answers (1)

Rob Napier
Rob Napier

Reputation: 299345

As you suspect, you can simplify the code with a simple map:

static func getNumberOfDistinctUsers(users: [ICEPKReferenceDataUser]) -> Int {
    return Set(users.lazy.map{$0.userName}).count
}

This uses the fact that you can initialize a Set using any other sequence.

I added lazy in there to avoid creating an extra copy of the array. It'll work with or without, but I expect it to be much more memory efficient this way. Array.map creates another Array. array.lazy.map return a lazy collection that computes values as requested.

That said, I don't know that my approach is dramatically better than your "brute-force" way. It's not obvious which is easer to read or maintain. I have a fondness for the map approach, but it can be a tradeoff (I had to know to add lazy for instance, or I could have allocated significant memory if this were a large array). Your code makes it very clear what's going on, so I don't think there's any problem that has to be solved there.

If you really wanted to use KVC, you'd need to convert your array to an NSArray, not an AnyObject, but I suspect that the above code is much faster, and is clearer and simpler, too, IMO.

Upvotes: 4

Related Questions