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.
Related
I have an array of dates/times. ("8/28/15, 2:38 PM") I'm trying to order it from newest to oldest date/time. What's the easiest most efficient way?
I was thinking of doing a for in loop and have an if statement checking if it goes before or after the item before the current one. But I'm sure there is better and more efficient way.
How can I sort arrays of time/date from oldest to newest? (If you need code I have, I can post it.
Array has a built-in method sort which allows you to provide a closure to sort the objects in it. Assuming your variable is called dates, you can sort the NSDates inside it like this:
dates.sort { (a, b) -> Bool in
a.earlierDate(b) == a
}
The sort method repeatedly asks you to compare two dates, asking for which one you want ordered first. You do this by using NSDate's earlierDate method to find the date which comes first.
Note: If your array is actually composed of strings of dates rather than NSDates, I'd recommend you convert them to NSDates first.
You may use this method
NSArray *sortedArray;
sortedArray = [unsorted_array sortedArrayUsingComparator:^NSComparisonResult(NSDate a, NSDate b) {
return [a compare:b];
}];
I have an array of categories returned from a parse.com query (sorted ascending) that are listed in a TableView.
I want to place a category called "Everything" at the top of the list and then sort the rest of the list ASC. I'm thinking I should use NSDescriptor, NSComparator or NSPredicate but wanted to get some feedback on the best route.
Another angle I thought might work is to extract "Everything" out of the array and put it in a string and then use 2 custom cells and put "Everything" on top.
Any advice on which option would be best? Or is there another route I missed?
I solved this by copying the results Array into a mutable Array and then sorted the Array.
NSMutableArray *sort = [[NSMutableArray alloc] initWithArray:self.objects];
id tmp=[sort objectAtIndex:6];
[sort removeObjectAtIndex:6];
[sort insertObject:tmp atIndex:0];
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.
I have a fairly large number of NSManagedObjects in an NSArray and need to check whether do any of them have the same value for a property. The obvious way is nested for loops however it will take ages to go through all of them as there are about a 1000 objects in the array.
for (NSManagedObject *object in array) {
for (NSManagedObject *secondObject in array {
if ([[object valueForKey:#"key"] isEqualTo:[secondObject valueForKey:#"key"]] &&
object != secondObject) {
NSLog(#"Sharing a property");
}
}
}
Any better way to do this? If there are 1000 objects that accounts to 1 000 000 comparisons, that might take some time.
You could use an NSDictionary. Each entry would be made from the following pair:
key would be equal to the selected NSManagedObjects attribute
value would be an NSArray of NSManagedObjects, that share this attribute's value
Get the list of key values for the objects in the array, then turn that into a set. If the size of the set is the same as that of the original array, there are no matches.
If you need to know which objects match, use a dictionary to create a multiset -- each key has an array of the objects as its value.
Creating your own keyed set class is also an option.
You can sort the array according to the values of that property.
Then a single loop over
the array is sufficient to find objects sharing the same value of the property.
I have two NSMutableArrays. The content of the first is numerically, which is paired to the content of the second one:
First Array Second Array
45 Test45
3 Test3
1 Test1
10 Test10
20 Test20
That's the look of both arrays. Now how could I order them so numerically so they end up like:
First Array Second Array
1 Test1
3 Test3
10 Test10
20 Test20
45 Test45
Thanks!
I would put the two arrays into a dictionary as keys and values. Then you can sort the first array (acting as keys in the dictionary) and quickly access the dictionary's values in the same order. Note that this will only work if the objects in the first array support NSCopying because that's how NSDictionary works.
The following code should do it. It's actually quite short because NSDictionary offers some nice convenience methods.
// Put the two arrays into a dictionary as keys and values
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:secondArray forKeys:firstArray];
// Sort the first array
NSArray *sortedFirstArray = [[dictionary allKeys] sortedArrayUsingSelector:#selector(compare:)];
// Sort the second array based on the sorted first array
NSArray *sortedSecondArray = [dictionary objectsForKeys:sortedFirstArray notFoundMarker:[NSNull null]];
Rather than keep two parallel arrays, I'd keep a single array of model objects. Each number from the first array would be the value of one property, and each string from the second array would be the value of the other property. You could then sort on either or both properties using sort descriptors.
Generally, in Cocoa and Cocoa Touch, parallel arrays make work while model objects save work. Prefer the latter over the former wherever you can.