I have an NSMutableArray which contain objects retrieved from CloudKit. Initially, I'm not doing any sorting so it's using whatever sorting order the records are retrieved. There are some user interactions where I would then need to sort it for specific purposes. However, I want to be able to undo that sorting and go back to the default order. But since the initial sorting is not specified by me, I'm wondering if there is a way capture that initial sorting order? I looked at the documentation for NSMutableArray and NSSortDescriptor and didn't see any sort of methods that I could call to do that. Is there a built in way that I'm missing or does anyone have a custom way of doing this?
Thanks!
AFAIK, NSArray (and therefore NSMutableArray) don't have any special default sorting. Their order is simply the order objects were added in the first place.
NSArray *arr1 = #[#1, #2, #3];
NSLog(#"%#", arr1); // (1, 2, 3)
NSArray *arr2 = #[#3, #1, #2];
NSLog(#"%#", arr2); // (3, 1, 2)
One solution to your problem is to store the initial array, and when the user wants to sort it, you copy the initial array, sort it and display it to the user, while keeping the original around. If the user wants to undo that, you just display the original array and get rid of the sorted copy.
Here is very basic pseudo-code:
NSMutableArray *originalArray = [self arrayFromCloudKit]; // fetch from CloudKit
// now the user wants it sorted alphabetically
NSMutableArray *alphabeticallySorted = originalArray.mutableCopy
[alphabeticallySortedsortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
[self storeOriginalArray:originalArray];
[self displayUIWithArray:alphabeticallySorted];
// but if the user changes their mind, you just fetch the original and delete the sorted
NSMutableArray *originalArray = [self getOriginalArray];
[self displayUIWithArray:originalArray];
Related
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];
I have a NSMutableArray of NSDictionaries. I would like to be able to filter dynamically.
For example, I have 3 types of filters
- area
- item
- type
if area is chossen then I would like to filter the Array with the area predicate, However if the user then chooses to filter item too, the currently filtered area array will then have the item filter applied too it.
However if the area filter is removed then I would like to show the new item filter.
It gets even more complicated when type is introduced, however I am struggling to get this to work correctly and don't really know where to start with the logic of it.
I can get the array to filter based off the last selected predicate. So if I choose area then items the current filter will only be items not both.
Try something like:
NSMutableArray *predicates = [NSMutableArray array];
if (...) {
[predicates addObject:...];
}
NSCompoundPredicate *p = [[NSCompoundPredicate alloc] initWithType:NSAndPredicateType subpredicates:predicates];
Where you add the individual predicates to the array if they are required. This is assuming that at least one predicate does need to be applied.
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.
How to insert the record with coredata at first position in table? currently if i add insertNewObjectForEntityForName it adds record to last.
Well, as far as i know this is not possible. However one thing you could do is manipulate how the objects are retrieved from the DB. For example, for such requirements it is often useful to have an NSDate property in your model class. While inserting objects into the DB, pass [NSDate date] for this property. And while pulling out objects from the DB, write a sorting algorithm which returns the records sorted by the Date of insertion
In your model class' header file
Header.h
//Declare this property
NSDate *dateOfInsertion
//This method returns objects sorted by DateOf Insertion
- (NSArray*)arraySortedByDateOfInsertion {
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"dateOfInsertion" ascending:NO];
return [self sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
}
Hope this helps
You cannot decide where to add element in the table. But you use array for this . You can add the element at the top of the array so it will appeared as a first row in the table :
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index
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.