How to combine two key values in the dictionary of array in Objective C - objective-c

I am having the multiple objects of the dictionary in the array. Now, in particular dictionary i have two keys "category" and "createdDate" from the other key.
Situation : -
I Need an array which having objects in a such a way that, the category which having the same date can be clubbed together and form an object . and Those category having different date is the other object it self.
I am having situation in my mind where i have to put various comparison conditions between the keys , the basic approach of doing it . --- Not Required
Need your valuable suggestion for Different Approach, Which is required, also is not complex. Thanks in advance.

here you go, an example
NSDateFormatter * df = [NSDateFormatter new];
for (id object in self.mainArray) {
[df setDateFormat:#"MM/dd/yyyy"];
NSString *dateString = [df stringFromDate:[object objectForKey:#"createdDate"]];
NSMutableArray *sectionArray = self.totalsSectionDictionary[dateString];
if (!sectionArray) {
sectionArray = [NSMutableArray array];
self.totalsSectionDictionary[dateString] = sectionArray;
}
NSString * tempString = [object valueForKey:#"category"]
[sectionArray addObject:#{#"value" : tempString}];
}
this results in a dictionary of objects combined by date as a string value and inside each one of those date keys resides an array of values for that date. From there, you need to tease out those values and sort them like so:
NSArray * tempUnsortedArray = [self.totalsSectionDictionary allKeys];
NSArray *arrKeys = [tempUnsortedArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"MM/dd/yyyy"];
NSDate *d1 = [df dateFromString:(NSString*) obj1];
NSDate *d2 = [df dateFromString:(NSString*) obj2];
return [d2 compare: d1];
}];
NSMutableArray * tempArray1 = [NSMutableArray array];
for (NSInteger i = 0; i < arrKeys.count; i++) {
NSMutableArray *sectionArray = self.totalsSectionDictionary[arrKeys[i]];
}
there you go, the last for loop will allow you to iterate through each section array stored in the original dictionary by date so you can put them into a collection or table view
good luck

Related

Subdividng an Array of Core data objects by attribute

I have an array of core data objects that have a time(date) attribute.
What I want to do is place all the core data objects that have the same time into separate arrays and then create an array of those arrays. If no other object has the same time then that object will be in an array by itself.
i.e If the array of core data objects had 3 objects with time 08:00 and 1 object with time attribute 09:00 then I want to create one array with the first 3 objects(time 08:00) and a separate array with the last object (time 09:00). Then I want to create an array of those arrays which should be easy enough. Start: [8,8,8,9] Finish: [[8,8,8][9]]
I am struggling most with how to iterate through my original array and pull out all the objects with the same time and then put those objects in their own array.
One of many ways to do this is using a NSDictionary object where the time is a key and the corresponding object is an array of core data objects that have this time. The core data objects are iterated once.
NSArray *data = core data objects
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
for (ManagedObjectClass *object in data) {
NSDate *time = object.time;
// convert time to time without date
NSMutableArray *array = dictionary[time];
if (!array) {
array = [NSMutableArray array];
dictionary[time] = array;
}
[array addObject:object];
}
NSArray *array = dictionary.allValues;
Another way to do this if the time doesn't need conversion: sort the core data objects by time, iterate the objects, start a new subarray when the time changes and add the object to the subarray.
NSArray *data = core data objects
NSArray *sortedData = [data sortedArrayUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"time" ascending:YES]]];
NSMutableArray *array = [NSMutableArray array];
NSMutableArray *subarray = nil;
NSDate *prevTime = nil;
for (ManagedObjectClass *object in sortedData) {
NSDate *time = object.time;
if (![time isEqualToDate:prevTime]) {
subarray = [NSMutableArray array];
[array addObject:subarray];
}
[subarray addObject:object];
prevTime = time;
}
You can do some thing like this:
Add a transient property in your coredata object.
Eliminate the minutes and seconds from your date in transient property.
Get distinct objects based on your transient property.
Filter objects from your main array and add them in a separate array.
Finally add them in final array.
Implementation can be like this:
MyObject *myObject1 = [[MyObject alloc] initWithDate:[NSDate dateWithTimeIntervalSinceNow:10*60]];
MyObject *myObject2 = [[MyObject alloc] initWithDate:[NSDate dateWithTimeIntervalSinceNow:10*60]];
MyObject *myObject3 = [[MyObject alloc] initWithDate:[NSDate dateWithTimeIntervalSinceNow:180*60]];
MyObject *myObject4 = [[MyObject alloc] initWithDate:[NSDate dateWithTimeIntervalSinceNow:120*60]];
MyObject *myObject5 = [[MyObject alloc] initWithDate:[NSDate dateWithTimeIntervalSinceNow:120*60]];
NSMutableArray *myObjects = [NSMutableArray arrayWithObjects:myObject1,myObject2,myObject3,myObject4,myObject5, nil];
NSArray *distinctObjects = [myObjects valueForKeyPath:#"#distinctUnionOfObjects.transientDate"];
NSMutableArray *finalArray = [NSMutableArray array];
for(NSDate *aDate in distinctObjects) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"transientDate == %#", aDate];
NSArray *filteredArray = [myObjects filteredArrayUsingPredicate:predicate];
[finalArray addObject:filteredArray];
}
NSLog(#"distintobjects: %#", finalArray);
Here is how MyObject looks like:
#import <Foundation/Foundation.h>
#interface MyObject : NSObject
{
}
#property(nonatomic, strong) NSDate *myDate;
#property(nonatomic, strong) NSDate *transientDate;
- (id)initWithDate:(NSDate *)aDate;
#end
#import "MyObject.h"
#implementation MyObject
- (id)initWithDate:(NSDate *)aDate {
self = [super init];
self.myDate = aDate;
return self;
}
- (NSDate *)transientDate {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy HH"];
return [dateFormatter dateFromString:[dateFormatter stringFromDate:self.myDate]];
}
- (NSString *)description
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy HH:mm"];
return [NSString stringWithFormat:#"transientDate: %#", [dateFormatter stringFromDate:self.transientDate]];
}
#end
Here is the final output:

Using NSNumber to sort numerous integers

Ive been doing alot of research and can't quite grasp resolving this issue. In my application I have several text fields that save integer values in the form of int variables (at least 15 int variables). My main goal is to sort out high to low numbers that were saved from the text fields.
Now would I use the following code to convert each seperate integer variable into a new NSNumber, than use a sort function to sort out the new NSNumbers from high to low?
NSNumber *newNumber = [NSNumber numberWithInt: my_int_variable];
I just feel as if this is a redundant way of sorting 12 integer variables and there is a easier way. Thank you for the help
Going from individual text fields to strings to ints to NSNumbers to an array to a sorted array is long, clunky trip. But a worthwhile trip nevertheless.
// assume these
UITextField *field0;
UITextField *field1;
UITextField *field2;
// make an array for the input and the result
NSArray *textFields = #[field0, field1, field2];
NSMutableArray *numbers = [#[] mutableCopy];
// prepare a number formatter
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
// lots of choices here. see https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSNumberFormatter_Class/index.html
for (UITextField *textField in textFields) {
NSString *text = textField.text;
NSNumber *number = [formatter numberFromString:text];
[numbers addObject:number];
}
// sort...a few choices here, too. taking the simplest:
[numbers sortUsingSelector:#selector(compare:)];
NSLog(#"ta da: %#", numbers);
Or did you want to sort the text fields based on their contents? Doable too:
NSMutableArray *textFields = [#[field0, field1, field2] mutableCopy];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
[textFields sortedUsingComparator: ^(id objA, id objB) {
NSString *textA = ((UITextField *)objA).text;
NSString *textB = ((UITextField *)objB).text;
NSNumber *numberA = [formatter numberFromString:textA];
NSNumber *numberB = [formatter numberFromString:textB];
return [numberA compare:numberB];
}];
NSLog(#"text fields in order of their contents: %#", textFields);

NSMutableDictionary losing object

I'm trying to store arrays of objects in an Mutable Dictionary, but it seems like the dictionary is losing some of my arrays (or maybe the arrays are losing the data?).
Anyways, here's where I'm at:
- (NSDictionary *)getTicketsByDay:(NSArray *)tickets {
// take an array of tickets and return a dictionary with dates (given by
// NSDateFormatterShortStyle) as keys and arrays of tickets as the values
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
// get NSDate object without time (only month, day, year)
unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSMutableDictionary *datesDict = [[NSMutableDictionary alloc] init];
for (Ticket *ticket in tickets) {
NSDateComponents *ticketDateNoTimeComponents = [calendar components:flags fromDate:[ticket createdAt]];
NSDate *ticketDateNoTime = [calendar dateFromComponents:ticketDateNoTimeComponents];
NSString *dateString = [formatter stringFromDate:ticketDateNoTime];
NSMutableArray *ticketArray = [datesDict objectForKey:dateString];
NSLog(#"%lu", [ticketArray count]);
if (ticketArray == nil) {
NSLog(#"it's here: %#", dateString);
ticketArray = [[NSMutableArray alloc] init];
}
[ticketArray addObject:ticket];
NSLog(#"%lu", [ticketArray count]);
[datesDict setObject:ticketArray forKey:dateString];
}
return datesDict;
}
But then on the console, at random places (although the same places every time), I get something like
41
41
42
0
it's here: 6/29/12
1
even though the key for the previous objects was also "6/29/12". I've also had it print all the keys in the dictionary and there is only 1.
So somewhere I'm losing my data. What's going on?
I should also mention that I'm on 10.7.4 and using ARC.
The code looks fine to me (if you include suggestions from #ConradShultz)
Note that you don't need to create the ticketDateNoTime since you're using a date format, it will always generate the short format string even if the date contains a time...
So your code could be simplified to:
- (NSDictionary *)getTicketsByDay:(NSArray *)tickets {
// take an array of tickets and return a dictionary with dates (given by
// NSDateFormatterShortStyle) as keys and arrays of tickets as the values
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
NSMutableDictionary *datesDict = [[NSMutableDictionary alloc] init];
for (Ticket *ticket in tickets) {
NSString *dateString = [formatter stringFromDate:[ticket createdAt]];
NSMutableArray *ticketArray = [datesDict objectForKey:dateString];
NSLog(#"%lu", [ticketArray count]);
if (ticketArray == nil) {
NSLog(#"it's here: %#", dateString);
ticketArray = [[NSMutableArray alloc] init];
[datesDict setObject:ticketArray forKey:dateString];
}
[ticketArray addObject:ticket];
NSLog(#"%lu", [ticketArray count]);
}
return datesDict;
}
From the looks of it you'll merely leak memory, and your way of replacing the dictionary entry with itself seems unusual (but I think it should work), but what makes you think you are loosing objects? You are printing the size of your array, which is different for different date strings, so maybe you just got a new date string which made it create a new array for that date?
And about the memory leaking/the unusual code: a more traditional way would be
NSMutableArray *ticketArray = [datesDict objectForKey:dateString];
if (ticketArray == nil) {
ticketArray = [[NSMutableArray alloc] init];
[datesDict setObject:ticketArray forKey:dateString];
[ticketArray release];
}
[ticketArray addObject:ticket];

Sort objects of array according to date wise in iphone dev?

I've objects of array, in each object i have different type of strings in one string i am getting date from xml parsing, now my task is that to sort whole data according to time wise(like before date then current date then after date). I am having two problems.
How to sort array on this structure like objects of arrays if simple
then it'll more easy for me?
Which function should I use to sort date wise?
One of several options would be using a comparator block. You didn't provide enough informations, so I made some assumptions:
The date string is at the 3rd index of the NSArrays
The date string looks like 31-12-2011
Code
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
array = [array sortedArrayUsingComparator: ^(id a, id b) {
NSArray *array1 = (NSArray *)a;
NSArray *array2 = (NSArray *)b;
NSDate *date1 = [dateFormatter dateFromString:[array1 objectAtIndex:2]];
NSDate *date2 = [dateFormatter dateFromString:[array2 objectAtIndex:2]];
return [date1 compare:date2]
}
But you should also consider to have an class representing the data.
In that case you would inter ate over the raw dater and create a object for every data set, put it in an NSMutableArray and sort this. similar.

Sort NSArray of date strings or objects

I have an NSArray that contains date strings (i.e. NSString) like this: "Thu, 21 May 09 19:10:09 -0700"
I need to sort the NSArray by date. I thought about converting the date string to an NSDate object first, but got stuck there on how to sort by the NSDate object.
Thanks.
If I have an NSMutableArray of objects with a field "beginDate" of type NSDate I am using an NSSortDescriptor as below:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
Store the dates as NSDate objects in an NS(Mutable)Array, then use -[NSArray sortedArrayUsingSelector: or -[NSMutableArray sortUsingSelector:] and pass #selector(compare:) as the parameter. The -[NSDate compare:] method will order dates in ascending order for you. This is simpler than creating an NSSortDescriptor, and much simpler than writing your own comparison function. (NSDate objects know how to compare themselves to each other at least as efficiently as we could hope to accomplish with custom code.)
You may also use something like the following:
//Sort the array of items by date
[self.items sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [obj2.date compare:obj1.date];
}];
But this does assume that the date is stored as a NSDate rather a NString, which should be no problem to make/do. Preferably, I recommend also storing the data in it's raw format. Makes it easier to manipulate in situations like this.
You can use blocks to sort in place:
sortedDatesArray = [[unsortedDatesArray sortedArrayUsingComparator: ^(id a, id b) {
NSDate *d1 = [NSDate dateWithString: s1];
NSDate *d2 = [NSDate dateWithString: s2];
return [d1 compare: d2];
}];
I suggest you convert all your strings to dates before sorting not to do the conversion more times than there are date items. Any sorting algorithm will give you more string to date conversions than the number of items in the array (sometimes substantially more)
a bit more on blocks sorting: http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html
What it worked in my case was the following:
NSArray *aUnsorted = [dataToDb allKeys];
NSArray *arrKeys = [aUnsorted sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"dd-MM-yyyy"];
NSDate *d1 = [df dateFromString:(NSString*) obj1];
NSDate *d2 = [df dateFromString:(NSString*) obj2];
return [d1 compare: d2];
}];
I had a dictionary, where all keys where dates in format dd-MM-yyyy. And allKeys returns the dictionary keys unsorted, and I wanted to present the data in chronological order.
You can use sortedArrayUsingFunction:context:. Here is a sample:
NSComparisonResult dateSort(NSString *s1, NSString *s2, void *context) {
NSDate *d1 = [NSDate dateWithString:s1];
NSDate *d2 = [NSDate dateWithString:s2];
return [d1 compare:d2];
}
NSArray *sorted = [unsorted sortedArrayUsingFunction:dateSort context:nil];
When using a NSMutableArray, you can use sortArrayUsingFunction:context: instead.
Once you have an NSDate, you can create an NSSortDescriptor with initWithKey:ascending: and then use sortedArrayUsingDescriptors: to do the sorting.
Swift 3.0
myMutableArray = myMutableArray.sorted(by: { $0.date.compare($1.date) == ComparisonResult.orderedAscending })
Change this
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
To
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Date" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
Just change the KEY: it must be Date always