Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I'm looking for the most efficient way to achieve the following task...
I have an array of Objects of type Foo, amongst other properties, Foo has a latitude and a longitude property. Given an array of many Foo's, I need to extract the Foo's with matching lat / long's into one new array.
I have implemented several solutions which are working, including iterating using a for loop, and a solution using an NSPredicate, but both of these methods involve multiple iterations through an array. This array could potentially have hundreds of thousands of records, so i'm looking for something i can use which will achieve the desired result in one pass.
EDIT: Adding some pseudo-code to describe the approach i've already taken and to better describe the problem...
NSMutableArray * matchingLocations = [[NSMutableArray alloc] initWithCapacity:0];
for (Foo * checkingFoo in fooArray) {
NSMutableArray * checkingArray = [NSArray arrayWithArray:fooArray];
[checkingArray removeObject:checkingFoo];
for (Foo * foo in checkingArray) {
// I have a method coded for comparing two coordinates
if (checkingFoo.coordinate == foo.coordinate) {
[matchingLocations addObject:checkingFoo];
}
}
}
NSSet will provide a collection of unique objects. In order to implement it properly however you need to define what does mean to be identical for the Foo object. You do that in your Foo class implementation rewriting the method isEqual: and the method hash.
In your Foo class:
- (BOOL)isEqual:(id)object {
return (self.coordinate == [(Foo *)object coordinate]);
}
- (NSUInteger)hash {
return ([self.coordinate hash]);
}
Then everywhere in your code you can just use:
NSArray *array; // Your array with multiple Foo objects potentiually duplicates
NSSet *set = [NSSet setWithArray:array];
Have a loo kat the Apple Documentation reference for:
[NSObject isEqual:] https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/isEqual:
[NSSet setWithArray:]
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSSet_Class/Reference/Reference.html#//apple_ref/occ/clm/NSSet/setWithArray:
You are running two fast enumeration as for loop of same array. Which is not correct. If you want to compare the co-ordinates then excecute for loop of different array. And also you can add directly to mutable array if same for loop only you are using.
If you want to compare objects from the array, then I suggest you use NSSet instead of NSArray.
It is very easy to use and the below link is something you want because I resolved such a case using NSMutableSet :
NSSet Tutorial
Related
This question already has answers here:
How can I sort an NSMutableArray alphabetically?
(7 answers)
Closed 8 years ago.
I have an NSMutableArray with this values:
how, format, anderson, babilon,
I would like to know if there is a command in which you can arrange this array in alphabetical order, so that the end result of the array becomes this:
anderson, babilon, format, how
observation -> my example above 4 items are specified in an array, but actually this array can store more than 1000 items, Someone can help me?
I would like to know if there is a command in which you can arrange
this array in alphabetical order, so that the end result of the array
becomes...
Yes. If you look at the NSMutableArray documentation you'll find a list of methods that can be used for sorting. They all start with the word "sort".
Apple also provides documentation on sorting arrays in the section named Sorting Arrays in Collection Programming Topics. For example, you could use the method -sortUsingSelector: this way:
NSMutableArray *names = [#[#"how", #"anderson", #"format", #"babilon"] mutableCopy];
[names sortUsingSelector:#selector(compare:)];
I am using NSUserDefault (user defaults) to determine whether "Lists Sort Ascending" - the lists obtained from my Core Data stack using an NSFetchedResultsController - are sorted ascending or not.
For example:
NSSortDescriptor *sortDescriptorPrimary = [NSSortDescriptor sortDescriptorWithKey:self.sortAttributePrimary ascending:listsSortAscending selector:#selector(compare:)];
Regardless of the user setting, there are two Entities for which this value will always be true i.e. BOOL listsSortAscending = YES;, to be specific, alphabetically sorted lists, such as a contact list.
The code following this sentence is an attempt to explain what I am attempting to achieve...
BOOL listsSortAscending = YES;
if ((![self.entity isEqualToString:#"Contact"]) || (![self.entity isEqualToString:#"TypeChild"])){
listsSortAscending = [self.userDefaults boolForKey:kListsSortAscending];
}
Apart from the lists for those two entities that will always be sorted ascending:YES, the other entities will be sorted based on the user default listsSortAscending.
This code does not work however and I cannot seem to work out the syntax correct.
I have read a lot of Stack Overflow and other pages including Objective-C IF statement with OR condition, however I cannot seem to resolve this annoying syntax!!!
The code included below does work, however my obsessive compulsive traits are running strong today and I want to learn the correct syntax using the OR operator ||.
BOOL listsSortAscending = YES;
if (![self.entity isEqual:#"Contact"]) {
if (![self.entity isEqual:#"TypeChild"]) {
listsSortAscending = [self.userDefaults boolForKey:kListsSortAscending];
}
}
Any suggestions please?
I think you want:
if ((![self.entity isEqualToString:#"Contact"] && ![self.entity isEqualToString:#"TypeChild"])) {
It isn't really a syntax thing, its a negation thing. Sometimes it's easier to specify the positive case instead of the negative case. But your second section of code with the nested ifs is actually an && rather than an ||.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
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];
}
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).
You may also look at modern block syntax: indexOfObjectWithOptions:passingTest: or indexesOfObjectsWithOptions:passingTest: which support concurrency and search order.
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
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
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.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Folks, I'm trying to do the following.
I've got a array (NSArray) called 'specialLevels', that array looks like this:
specialLevels = #[#2, #4, #6, #9];
This should be a array of int's.
I also got the int 'currentLevel' (basic int no object).
And I want to check if the currentLevel is in de array of specialLevels.
I know the method 'containsObject' exists, but this won't work in my case.
What would you guys recommend to do in this case?
So I thought this, but it feels kinda strange imo:
if ([specialLevels containsObject:[NSNumber numberWithInt:currentLevel]]) {
// other code in here
}
You could alternatively write:
if ([specialLevels containsObject:#(currentLevel)]) {
// other code in here
}
which is more in keeping with the style of your other code.
specialLevels is not an array of ints. It is an array of NSNumber objects. #2, #4, #6, #8 each create an NSNumber instance equivalent to calling [[NSNumber numberWithInt:value]. When you call containsObject you also need to pass an NSNumber object so that containsObject can match the value (using isEqual:).
You can read about Objective-C literals here.
Here is my situation:
I manipulate 6 NSMutableArrays. One of them has NSDates objects in it, the other ones have NSNumbers. When I populate them, I use addObject: for each of them, so index 0 of each array contains all the values I want for my date at index 0 in the dates array.
I want to make sure that the arrays are all sorted according to the dates array (order by date, ascending), meaning that during the sorting, if row 5 of the dates array is moved to row 1, it has to be applied to all the other arrays as well.
I was previously using CoreData, but I must not use it anymore (please don't ask why, this is off-topic ;) ). In CoreData, I could use an NSSortDescriptor, but I have no idea on how to do it with multiple NSArrays...
As always, hints/answers/solutions are always appreciated :)
This is a common problem. Use the following approach.
Encapsulate your six arrays into an object - every instance will have six properties.
Implement compare: method on this object, using [NSDate compare:] (this step can be skipped but it's cleaner this way).
Now you have only one array - sort it using the method from step 2.
I think the better solution for you to have NSArray of NSDictionary objects.
NSArray *allValues = [[NSArray alloc] init];
NSDictionary *dict = #{"Date" : [NSDate date], #"Key1" : #"Value1", #"Key2" : #"Value2"};
Then you can sort this array with sortDescriptor without any problems.
And then you can also use Comparator or Sort Desriptor as you wish.
Wrap all your items that you are storing in an array into a single object. Each one of your previous 6 arrays will be a property.
Inside that object you can implement
- (NSComparisonResult)compare:(YourClass *)otherObject {
return [self.date compare:otherObject.date];
}
You can now sort the array and they will sort by date.