NSMutableArray Sorting and grouping with memory Optimisation - objective-c

NSArray has ItemObject's in it. This ItemObject's are not grouped based on ItemID
The Sample of the json is displayed below:
You will note the itemIDs "a123","a124". There can be n number of itemIDs.
[
{
"ItemName": "John",
"ItemID": "a123"
},
{
"ItemName": "Mary",
"ItemID": "a124"
},
{
"ItemName": "Larry",
"ItemID": "a123"
},
{
"ItemName": "Michel",
"ItemID": "a123"
},
{
"ItemName": "Jay",
"ItemID": "a124"
}
]
The above response is stored in NSArray as follows:
NSMutableArray *itemArray=[[NSMutableArray alloc] init];
ItemObject *obj=[[ItemObject alloc] init];
obj.itemName=#"John";
obj.itemID=#"a123";
[itemArray addObject:obj]
.....
ItemObject *objN=[[ItemObject alloc] init];
objN.itemName=#"Jay";
objN.itemID=#"a124";
[itemArray addObject:objN].
This shows, if there are N items in JSON, then it will create a array of N items.
The above item is displayed correctly in UItableView.
Now, if want to sort them and put them in NSMutableArray group wise what will be optimal way to code it, with less memory footprint to be consumed. [i.e sorting + grouping]
I am trying to achieve the below:
NSMutableArray *itemArray=[[NSMutableArray alloc] init];
at index 0: NSArray with itemID "a123"
at index 1: NSArray with itemID "a124"
Since, available ItemIds, are dynamic, as I explained there can be "N" number of itemId's.
Step 1:
So, I first need to find the available itemId's.
Step 2:
NSMutableArray *myArray=[[NSMutableArray alloc] init];
for(NSString *itemID in itemIDS){
NSArray *itemsForID=[itemArray filterUsingPredicate:[NSPredicate predicateWithFormat:"itemID MATCHES %#",itemID]];
[myArray addObject:itemsForID];
}
myArray is the expected result.
But using filterUsingPredicate "N" number of times will be time and memory consuming.
Any, help Appreciated.

Can you please try the below code?
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"itemID" ascending:YES];
[itemArray sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];

You could persist your data as NSManagedObjects. Then you can use an NSFetchedResultsController as data source for your table (you set a sort descriptor and a section name key path to it):
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:nil
cacheName:nil];
You can also set the batch size (the max number of objects taken from the DB at a time).
Hope this helps!

Related

How to sort NSDictionary using millisecond (Time format)?

I have a Dictionary of format [Int:Any] I have bunch of key value pairs in it. I want to sort out the dictionary using the millisecond time format
[169887: ["noti_type": 0, "project_name": "Design Project", "eventCount": 6, "author_pic": " /file/download/profile$2348d4f21095a01cc16a8ad9bf08f966.jpg", "canvas_name": "Design Reference #31 : Windows in NYC", "lastUpdatedAt": 1513585053629, "author_name": "Jake Kyung "],
173865: ["noti_type": 0, "project_name": "BeeCanvas DEV", "eventCount": 13, "author_pic": " &&&& /file/download/profile$80bbc9731a859d4e083df0df8044bcde.jpg &&&& /file/download/profile$2348d4f21095a01cc16a8ad9bf08f966.jpg", "canvas_name": "Android Release note", "lastUpdatedAt": 1513307315308, "author_name": " &&&& Sukho Bu &&&& Jake Kyung "]
I have a bunch of these kind of values in my Dictionary. I want to sort them using the lastUpdatedAt value which is 1513585053629 millisecond format.
I have gone through some posts which said this is possible if I can use a NSDate,
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey: #"dateOfInfo" ascending: NO];
NSArray *sortedArray = [array sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
But I was just wondering if I could achieve this directly using the millisecond format instead of converting to NSDate ?
This is just demo for understanding..
NSMutableDictionary *dict1 = [[NSMutableDictionary alloc]init];
[dict1 setObject:#"Design Project" forKey:#"project_name"];
[dict1 setObject:#"1513585053629" forKey:#"lastUpdatedAt"];
NSMutableDictionary *dict2 = [[NSMutableDictionary alloc]init];
[dict2 setObject:#"BeeCanvas DEV" forKey:#"project_name"];
[dict2 setObject:#"1513307315308" forKey:#"lastUpdatedAt"];
NSMutableArray *arr = [[NSMutableArray alloc]init];
[arr addObject:dict1];
[arr addObject:dict2];
NSLog(#"original array = %#",arr);
you can give directly key name in sort descriptor.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey: #"lastUpdatedAt" ascending:YES];
NSArray *sortedArray = [arr sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSLog(#"sorted array = %#",sortedArray);
Output:-
sorted array = (
{
lastUpdatedAt = 1513307315308;
"project_name" = "BeeCanvas DEV";
},
{
lastUpdatedAt = 1513585053629;
"project_name" = "Design Project";
}
)

Objective-C append dictionary to NSDictionary

i need to send data to server with NSDictionary. The data will be name, gender dll, is coming from text field. I know i can save one dictionary like this.
NSDictionary * = #{#"employee": #"EmpA",
#"gender":#"Male",
#"pob":#"SF",
#"age":#"27",
};
But i need to add multiple data because i have button that can repeat the form procedure. After that i will send the whole data to server based on format below.
"employee": [{
"name": "EmpA",
"gender": "Male",
"pob": "SF",
"age": 27
}, {
"name": "EmpB",
"gender": "Female",
"pob": "TX",
"age": 36
}]
How i can dynamically append the dictionary?
Thanks
Use an Array of dictionaries :
NSMutableArray *employees= [[NSMutableArray alloc] init];
for(//loop through the forms) {
NSDictionary *emp = #{#"name": #"EmpA",
#"gender":#"Male",
#"pob":#"SF",
#"age":#"27",
};
[employees addObject:emp];
}
NSDictionary *payload = #{#"employee": employees};
I dont have a mac at hand so forgive any syntax errors.
You need to create an array of dictionaries and insert it in your "employee" key. Something like this should work:
NSMutableDictionary *employee = [[NSMutableDictionary alloc]init];
NSMutableDictionary *emplyeeA = [#{#"name": #"EmpA", #"gender": #"Male", #"pob": #"SF", #"age": #"27"} mutableCopy];
NSMutableDictionary *emplyeeB = [#{#"name": #"EmpB", #"gender": #"Female", #"pob": #"TX", #"age": #"36"} mutableCopy];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
[tempArray addObject: emplyeeA];
[tempArray addObject: emplyeeB];
[employee setObject:tempArray forKey:#"employee"];

Sorting of array of dictionaries by using key of dictionary

{
"restaurant name" : "str1",
"distance": 19.4
}
{
"restaurant name" : "str2",
"distance": 2.1
{
"restaurant name" : "str3",
"distance":19.3
}
{
"restaurant name" : "str4",
"distance": 2.1
}
Above is my array of dictionary values restaurant name and key. I have used following code but it is not sorting properly. It is showing sequence 19.3 ,19.4, 2.1, 2.1. I think it is comparing only first digit
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:kRestaurantListDistance ascending:YES selector:#selector(compare:)];
[restaurantList sortUsingDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
Please tell me proper code to sort out array in ascending order.
You can maybe try this :
array = [[NSMutableArray alloc] initWithArray:[array sortedArrayUsingComparator:^(id obj1, id obj2) {
float distance1 = [[obj1 objectForKey:#"distance"] floatValue];
float distance2 = [[obj2 objectForKey:#"distance"] floatValue];
if (distance1 < distance2) {
return (NSComparisonResult)NSOrderedDescending;
} else if (distance1 > distance2) {
return (NSComparisonResult)NSOrderedAscending;
} else {
return (NSComparisonResult)NSOrderedSame;
}
}]];
If it's sorting by the first digit, that means that your numbers are, in fact, just strings.
Two possible approaches:
Before you sort then, convert them to numbers (it's in a dictionary, so they'll have to be NSNumbers rather than simple floats)
Create your own compare method or block (I typically prefer to use initWithKey:ascending:comparator:)
Which approach you use depends on what you do with the dictionary afterwards. If you need numbers again later, 1 is probably best; otherwise 2.
You can maybe try this. it will work :
arrWholeArrImg=[NSMutableArray sortArray:_arrWholeArrImg string:#"CategoryName"];
+(NSMutableArray *)sortArray:(NSMutableArray *)arr string:(NSString *)key {
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:key
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [arr sortedArrayUsingDescriptors:sortDescriptors];
arr = [sortedArray mutableCopy];
return arr;
}

Sort NSMutableArray based on strings from another NSArray

I have an NSArray of strings that I want to use as my sort order:
NSArray *permissionTypes = [NSArray arrayWithObjects:#"Read", #"Write", #"Admin", nil];
I then have a NSMutableArray that may or may not have all three of those permissions types, but sometimes it will only be 2, sometimes 1, but I still want it sorted based on my permissionsTypes array.
NSMutableArray *order = [NSMutableArray arrayWithArray:[permissions allKeys]];
How can I always sort my order array correctly based on my using the permissionTypes array as a key?
I would go about this by creating a struct or an object to hold the permission types.
Then you can have...
PermissionType
--------------
Name: Read
Order: 1
PermissionType
--------------
Name: Write
Order: 2
and so on.
Then you only need the actual array of these objects and you can sort by the order value.
[array sortUsingComparator:^NSComparisonResult(PermissionType *obj1, PermissionType *obj2) {
return [obj1.order compare:obj2.order];
}];
This will order the array by the order field.
NSMutableArray *sortDescriptors = [NSMutableArray array];
for (NSString *type in permissionTypes) {
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:type ascending:YES] autorelease];
[sortDescriptors addObject:descriptor];
}
sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];
Use whichever sorting method on NSMutableArray you prefer, you will either provide a block or a selector to use for comparing two elements. In that block/selector rather than comparing the two strings passed in directly look each up in your permissionTypes array using indexOfObject: and compare the resulting index values returned.
I suggest you another approuch:
- (void)viewDidLoad
{
[super viewDidLoad];
arrayPermissions = [[NSMutableArray alloc] init];
NSDictionary *dicRead = [NSDictionary dictionaryWithObjectsAndKeys:
#"Read", #"Permission", nil];
NSDictionary *dicWrite = [NSDictionary dictionaryWithObjectsAndKeys:
#"Write", #"Permission", nil];
NSDictionary *dicAdmin = [NSDictionary dictionaryWithObjectsAndKeys:
#"Admin", #"Permission", nil];
NSLog(#"my dicRead = %#", dicRead);
NSLog(#"my dicWrite = %#", dicWrite);
NSLog(#"my dicAdmin = %#", dicAdmin);
[arrayPermissions addObject:dicRead];
[arrayPermissions addObject:dicWrite];
[arrayPermissions addObject:dicAdmin];
NSLog(#"arrayPermissions is: %#", arrayPermissions);
// create a temporary Dict again
NSDictionary *temp =[[NSDictionary alloc]
initWithObjectsAndKeys: arrayPermissions, #"Permission", nil];
// declare one dictionary in header class for global use and called "filteredDict"
self.filteredDict = temp;
self.sortedKeys =[[self.filteredDict allKeys]
sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"sortedKeys is: %i", sortedKeys.count);
NSLog(#"sortedKeys is: %#", sortedKeys);
}
hope help

Sort an NSArray with NSDictionary

I'm using NSSortDiscriptors to sort an NSArray.
Every index in the array contains a dictionary with key,value entries. This dictionary also holds another dictionary.
My problem that I want solve is to sort the array based on values on the first dictionary, but also on some values in the dictionary it contains.
The following is the sort method I use for the other values in the array.
- (void)sortArray {
if ([array count] != 0) {
// Reports sortingDescriptors
NSSortDescriptor * city = [[NSSortDescriptor alloc] initWithKey:#"City" ascending:YES];
NSSortDescriptor * name = [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:YES];
NSSortDescriptor * country = [[NSSortDescriptor alloc] initWithKey:#"Country" ascending:YES];
[reportsArray sortUsingDescriptors:[NSArray arrayWithObjects:city, name, country, nil]];
[name release];
[city release];
[country release];
}
}
The array looks like this:
[{name = "";
city = "";
country = "";
date = {
dateAdded = "";
dateRemoved = "";
}
}];
So I also want to sort on, if have value on dateAdded for example.
You can specify a key path when you create the NSSortDescriptor, this way you can sort the NSArray with a NSDictionary.
You might want to check if the dictionary contains a value like that :
// you can't set nil as a value for a key
if([yourDictionary objectForKey:#"yourKey"] == [NSNull null]) { ... }
Then you need to sort remaining objects but the dictionary, to do so, make a copy of your array without the dictionary entry by doing something like :
NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:firstArray];
[tmpArray removeObjectAtIndex:theIndexOfTheDictionary];
// sort your array, don't forget to catch the returned value
NSMutableArray *sortedArray = [tmpArray sortUsingDescriptors:[NSArray arrayWithObjects:city, name, country, nil]];
// finally, put the dictionary back in (if needed)
[sortedArray insertObject:theDictionary atIndex:theIndexYouWant];
Are you saying that the objects in the array have a City, Name and Country property but also a dictionary property and you want to sort on one of the keys in the dictionary? Or are you saying that the entries in the array are dictionaries but sometimes the City, Name or Country key is missing? Or are you saying that some of the entries are dictionaries and some are objects with the listed properties?
In any case, you can get more flexibility by creating a sort descriptor using initWithKey:ascending:comparator:. This allows you to supply a comparator block as the sort function which is more flexible than a straight selector e.g.
NSComparator mySort = ^(id obj1, id obj2)
{
NSComparisonResult ret = NSOrderedSame;
if ([obj1 isKindOfClass: [NSDictionary class]] && ![obj2 isKindOfClass: NSDictionary class]])
{
ret = NSOrderedAscending;
}
else if (![obj1 isKindOfClass: [NSDictionary class]] && [obj2 isKindOfClass: NSDictionary class]])
{
ret = NSOrderedDescending;
}
return ret;
};
NSSortDescriptor* descriptor = [[NSSortDescriptor alloc] initWithKey: #"self" ascending: YES comparator: mySort];
will give you a sort descriptor that sorts the array putting all the NSDictionaries first and other objects afterwards. (self is a key possessed by all NSObjects that returns the object itself).
NSArray *unsortedArray=[NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:#"anil",#"personInDictionary.lastName" ,nil],[NSDictionary dictionaryWithObjectsAndKeys:#"aneelu",#"personInDictionary.lastName", nil] ,[NSDictionary dictionaryWithObjectsAndKeys:#"kumar",#"anil.lastName", nil] ,nil];
NSSortDescriptor * descriptor = [[[NSSortDescriptor alloc] initWithKey:#"personInDictionary.lastName" ascending:YES] autorelease]; // 1
NSArray * sortedArray = [unsortedArray sortedArrayUsingDescriptors:
[NSArray arrayWithObject:descriptor]];
NSLog(#"sortedArray values %#",sortedArray);
for (id object in [sortedArray valueForKey:#"personInDictionary.lastName"]) {
NSLog(#"sortedArray value %#",object);
}