NSArray find object or objects - best practices [closed]

霸气de小男生 提交于 2019-12-04 09:10:31

问题


Solution: I have marked @BlackRider's answer as correct as it is the most versatile especially for complex comparisons however there are other very good answers and comments. I would encourage anyone with the same or similar question to review them and evaluate the best course of action for your specific situation.

In my situation, I am actually not using BlackRider's solution in my implementation. I have elected to use my own solution (see Edit #2 below) with help from @JoshCaswell's comments as well as @voromax's suggestion of indexesOfObjectsWithOptions:passingTest: due to the fact that my comparisons are very simple in this situation.

Thanks to everyone who answered and provided insight.


I am looking for an efficient way to retrieve an object from an NSArray based on a property of that object (a unique identifier, in this case). In C#.NET using Linq I would do something like

MyObject obj = myList.Single(o => o.uuid == myUUID);

I am also wondering if there is an efficient way to get an array of objects matching a non-unique property. Again, with Linq it would look like

List<MyObject> objs = myList.Where(o => o.flag == true).ToList();

Of course I can write loops to do this but they would not be reusable and I'm suspicious of their performance.

Finding an object with a unique ID:

-(MyObject*)findObjectWithUUID:(NSString*)searchUUID{
    for (MyObject* obj in _myArray){
        if([obj.uuid isEqualToString: searchUUID])
            return obj;
    }
}

Finding an array of objects:

-(NSArray*)findObjectsWithFlag:(BOOL)f{
    NSMutableArray* arr = [NSMutableArray array];
    for (MyObject* obj in _myArray){
        if(obj.flag == f)
            [arr addObject:obj];
    }
    return arr;
}

-- EDIT --

Luckily in the first situation the object I am looking for has a unique identifier and I know there will only be one. I came up with a solution to implement isEqual on my object which will be invoked by indexOfObject:

- (BOOL)isEqual:(id)object{
    return [self.uuid isEqualToString: ((MyObject*)object).uuid];
}

And then create a "fake" lookup object and use that to find the real one

MyObject *lookupObject = [[MyObject alloc] init];
lookupObject.uuid = searchUUID;
MyObject *actualObject = 
    [_myArray objectAtIndex:[_myArray indexOfObject:lookupObject]];

This is essentially the same as the for-in loop I posted above, but might be more readable & be more reusable. Of course, this only works for finding one unique object and does not address the second half of my question.

-- EDIT 2 --

Checking Class and implementing hash as recommended in comments.

- (BOOL)isEqual:(id)object{
    return [object isKindOfClass:[MyObject class]] && 
           [self.uuid isEqualToString: ((MyObject*)object).uuid];
}

- (NSUInteger)hash{
    return [self.uuid hash];
}

回答1:


You can use [NSPredicate], which gives you a query-like syntax for search. Check out this page for the predicate syntax description. Here's a simple example:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"propertyName == %@", @"value"];
NSArray *filteredArray = [myArray filteredArrayUsingPredicate:predicate];

As to performance, I think your solution is OK since any search in an array needs to iterate through all the elements anyway, and then, for each object, compare the value of a field against the value you search for. You can optimize repeat searches within the same data, e.g. by creating and populating a dictionary that maps values of some field to the matching objects (or collections of objects, if the mapping is one to many).




回答2:


You may also look at modern block syntax: indexOfObjectWithOptions:passingTest: or indexesOfObjectsWithOptions:passingTest: which support concurrency and search order.




回答3:


I was intrigued by rmaddys comment so I've checked the difference between looping and predicate.

Let's assume a simple object with NSString property. I've inserted it into array 10 000 times , every time with different property value.

In the worst case scenario when desired object was on the last position of the array, loop approach was 3.5x faster than NSPredicate (0.39s vs 0.11s, arraySize = 10000, 10 iterations, iPad Mini)

Code I used for reference: pastebin




回答4:


just for those who are interested, I've found the fastest way to search through NSArray is by using a for loop on a background thread. using the [self performSelectorInBackground...] method. In an NSArray of 10000 custom objects I searched through the whole thing thoroughly in around 1 second. On the main thread it took around 10 seconds or more.




回答5:


I know its related with NSArray but if we do it using Swift and using the swift Array which is a struct, then that will be lot easier.

Swift 2.2 / Swift 3.0 / Swift 4.x Working fine on all versions

Lets assume we have a custom model class

class User {
    var userId = 0
    var userName = ""
} 

And lets assume we have an array named as usersArray which has custom objects of User class.

And we want to fetch an object from this array with userId = 100 for example:-

let filteredArray = usersArray.filter({$0.userId == 100}) 

This filtered array will contain all the custom objects which have userId as 100

print(filteredArray[0].userName) //will print the name of the user with userId = 100


来源:https://stackoverflow.com/questions/20024937/nsarray-find-object-or-objects-best-practices

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!