iOS, Sort allKeys of NSDictionary - ios

<-- Why have i been down voted? At least comment some reasoning
I have an incoming JSON array which details consecutive & non-consecutive date periods.
An example:
(Please note, the root index values are for example clarity. The real data is just associative key-value)
[0] => '01/01/2015 - 05/01/2015' : ['01/01/2015',
'02/01/2015',
'03/01/2015',
'04/01/2015',
'05/01/2015'],
[1] => '01/02/2015 - 05/02/2015' : ['01/02/2015',
'02/02/2015',
'03/02/2015',
'04/02/2015',
'05/02/2015'],
[2] => '25/03/2015': '25/03/2015',
[3] => '01/04/2015': '01/04/2015'
My final intention is to display each associative key in a UITableView, where consecutive date cells (indexes [0] & [1] in the example), on select will segue to another UITableView listing each individual date of the consecutive block. Non-consecutive date cells, (index [2] & [3] in example) will not be selectable to the user as there is nothing more to see. savvy?
My issue is that i import the JSON array into both an NSArray, & NSDictionary. (The reader should be aware that arrays are ordered, where as dictionaries are not)
NSArray of the imported data is structured true. The issue is i have no way of displaying the keys in the first UITableView, from which the 2nd UITableView can be populated with the relating value.
I take an NSArray of allKeys of the NSDictionary, which gives me the structured array of the keys of the un-structured dictionary. This i can use to display in the first UITableView, however its representation of data structure is not true to the imported structure. Its all jumbled & different each time.
My question is how the hell do i do this? but i should imagine that question may not be specific enough.... so, How would i sort the allKeys array of the dictionary in date order?
If your thinking, "Well this is easy! just sort using a descriptor",
like this one...?
NSSortDescriptor *descriptor=[[NSSortDescriptor alloc] initWithKey:#"self" ascending:NO];
NSArray *descriptors=[NSArray arrayWithObject: descriptor];
NSArray *reverseOrder=[self.dateKeys sortedArrayUsingDescriptors:descriptors];
Sadly, that would be too easy. That works fine with non-consecutive date keys, or single dates, but where i have consecutive date keys, '01/01/2015 - 05/01/2015' it fails. The overall NSArray is closer to the true imported data structure, but not close enough

You could map the response into an NSArray, where each item is an NSDictionary with a key (the range) and either an NSArray of values (the dates) or an NSString (single date).
Example:
NSArray *data = #[
#{
#"01/01/2015 - 05/01/2015" : #[
#"01/01/2015",
#"02/01/2015",
#"03/01/2015",
#"04/01/2015",
#"05/01/2015"
]
},
#{
#"25/03/2015" : #"25/03/2015"
}
];
Then, you can fill the first UITableView from the the main array, so from each item in the array, you get the dictionary key.
NSMutableArray *table1Data = [[NSMutableArray alloc] initWithCapacity:data.count];
for (NSDictionary *dateRange in data) {
[table1Data addObject:[[dateRange allKeys] firstObject]];
}
And the second UITableView is filled from the value of the dictionary (array of dates) of the selected item in the main array, only when the value is an NSArray:
id table2Data = [[data[selectedIndex] allValues] firstObject];
if ([table2Data isKindOfClass:[NSArray class]]) {
// Navigate to second view, passing table2Data as the second table view data.
// Cast table2Data to an NSArray if needed.
}
else {
// Do not navigate to the second view
}

If I read you correctly, you want to show one TableView with the date ranges (keys) in chronological order as follows:
Row 1: 01/01/2015 - 05/01/2015
Row 2: 01/02/2015 - 05/02/2015
Row 3: 25/03/2015
Row 4: 01/04/2015
And then, when tapping into row 1 or 2, show all the dates in the range in another TableView, i.e. for Row 1:
Row 1: 01/01/2015
Row 2: 02/01/2015
Row 3: 03/01/2015
Row 4: 04/01/2015
Row 5: 05/01/2015
You do need to store this data in an NSDictionary *dateRanges but as you are dealing with strings you need to encapsulate these date ranges in new classes which will make it easier to sort their values.
For instance, you may have a DateRange class with two #properties of type NSDate: startDate and endDate, where endDate is nil for those single dates (i.e. 25/03/2015) . You can then use an NSSortDescriptor to sort by startDate for the [dateRanges allKeys]:
NSArray *dateKeys = [self.dateRanges allKeys];
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"startDate" ascending:NO];
NSArray *reverseOrder = [dateKeys sortedArrayUsingDescriptors:#[ descriptor ]];

Related

IOS/Objective-C: Search string element with array of objects

As part of an autocomplete box, I am searching names within an array of contacts. However, after the user picks a name from the suggested List, I need to grab the id of the contact which is in the array of contact objects but not the array of names that appear in the suggest box. I've been working with just the names as that's what I want to display in the suggestion box but have an array of contacts as well.
How would I convert code below (probably using key values) to search the name dimensions of an array of objects instead of an array of names so as to keep track of the ids of the objects. I am kind of fuzzy on arrays and key values.
//the array being searched looks something like #[#"John", #"Dave", #"Sam", #"Xian", #"Ahmed", #"Johann"];
//I want to search the names in an array that looks something like:
(
{
first = "John";cid = 2;},
{
first = "Dave";cid = 44;},
{
first = "Xian";cid=99})
//this code works great to search names but I lose track ids. Thank you for any suggestions.
-(void)searchArray: (NSMutableArray*) array forString: (NSString *) term {
[_contactsSuggested removeAllObjects];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",term];
NSArray *tempArray = [array filteredArrayUsingPredicate:predicate];
_contactsSuggested = [NSMutableArray arrayWithArray:tempArray];
[_autocompleteTableView reloadData];
}
Create a Contact object. Give it a name property, an id property, and any other properties you need. Then write code that searches an array of Contact objects rather than just an array of names. You could then create a predicate using predicateWithBlock to filter the items that match your name property.

How can I implement my logic properly to populate my UITableView

Sorry guys, this problem I am running into is pretty trivial. I just can't wrap my head around it so hope someone can help me. Your help is really appreciated. I am getting JSON data through NSURLConnectDelegate with a web API. I get something like this back:
(
{
id = 340
name = Vicent },
{
id = 339
name = Johny },
{
id = 338
name = Eric }
)
and I save it in a NSMutableArray as a global variable. Now, I have a NSSet of "ids". For example:
{
340, 339
}
In the numberOfRowsInSection, I return the set's count. I am trying to load only the ids in the NSSet from the array with the data saved from the webAPI, so I do something like this in cellForRowIndexPath:
for (NSNumber *num in [set allObjects]) {
NSString *newString = [[savedArray objectAtIndex:indexPath.row]
NSString *new = [num stringValue];
if ([new isEqual:newString]) {
}}
How can I just populate the ids I want?
The JSON makes it look like you have an array of dictionaries, which is a reasonable data structure to use as the data source for a table view.
It sounds like you're trying to filter your array to only include the items that are in your set. Is that right?
If so, you could write code that would create a new array containing the subset of your array elements who's ID is also in your set. There are at least a half-dozen ways to do that. One fairly simple approach would be to use the NSArray method indexesOfObjectsPassingTest. You'd pass that method a block of code that would check each array element to see if it's id object was in your set.
That would give you an NSIndexSet with the indexes of the items in your array who's ID are in your set. Then you could use the NSArray method objectsAtIndexes to get an array of only the objects that are also in the set. Something like this (Assuming that your array of dictionaries is called savedArray and your set is called allObjects:
//get the indexes of items in the array savedArray who's id appears in the set allObjects
NSIndexSet *indexes = [savedArray indexesOfObjectsPassingTest:
^(NSDictionary *obj,
NSUInteger idx,
BOOL *stop)
{
return [allObjects member: obj[#"id"]] != nil;
}
];
//Now build an (immutable) array of just the objects who's ID are in the set
NSArray *subArray = [savedArray objectsAtIndexes: indexes];
The array subArray created above is immutable. If you need a mutable array you would need to make a mutable copy, which is a one-line change.
Disclaimer: I still struggle a little with block syntax, so the above might not be exactly correct, but it gives you the general idea.

Dictionary key-value using with array

I have an array and it has lots of dictionary's keys it comes from API. My array as follows
Dictionary keys array :
NSArray *arr = #[#"01", #"02", #"03"];
Dictionary with key-value pairs
NSDictionary *dic = #{#"01": #"Hero", #"02" : #"Enemy", #"03" : #"Boss"};
Basically i want to match array values corresponding to dictonary keys without using array. I found a solition about that but I don't want to use for-loop for every cell(I have a lots of cell). My solution is like that
for(NSString *item in arr) {
[convertedArr addObject:[dic valueForKey:item]];
}
NSLog(#"%#", [convertedArr componentsJoinedByString:#","]);
Asumme have an array like this (1,2,3) and dictionary looks like {1 = "a", 2 = "b", 3 = "c"} I just want to give an array and it should return dictionary values like this ("a","b","c")
Anybody should give me better approach without using array? Thanks.
You can replace your for-loop by
NSArray *convertedArr = [dic objectsForKeys:arr notFoundMarker:#""];
which is at least less code. (The notFoundMarker: is added for all keys
in the array which are not present in the dictionary. Your code would crash
in that situation.)
It might perform slightly better because it is a library
function. But I doubt that the difference is big, because in any case a dictionary
loopup is required for all keys in arr.

Non-relative NSArray sort

I want to sort an NSArray of NSStrings by similarity to a single given string, as opposed to relative sort order for items within the array.
Or to put it a different way, I want to sort the array by comparing all the items contained in the array by similarity to a single item, not sort them by comparing each other.
I have the logic for similarity figured out, it's just how I use the NSArray and/or NSSortDescriptor APIs to achieve this.
sortedArrayUsingComparator should allow you to achieve this ...
NSArray* sourceArray = //... your data
NSString* itemToCompareTo = sourceArray[5]; // locate the item you want to compare to
NSArray* sortedArray = [listItem sortedArrayUsingComparator: ^(id a, id b) {
// compare a, b, and itemToCompareTo here, using your sort logic
}

appending strings to NSMutableArray in NSMutableDictionary

I need to append strings to an array kept inside of a dictionary each time a word matches a pattern of another word. The second line below (setObject) overwrites instead of appending.
The end result should be arrays in a dictionary where the the key(pattern) identifies many strings that fit that pattern.
NSMutableDictionary *eqClasses = [[NSMutableDictionary alloc] init];
[eqClasses setObject:tempWordStr forKey:wordPattern];
Is there an easy way to append?
Try this:
NSMutableArray* array = [eqClasses objectForKey:wordPattern];
if(!array) {
// create new array and add to dictionary if wordPattern not found
array = [NSMutableArray array];
[eqClasses setObject:array forKey:wordPattern];
}
[array addObject:tempWordStr];
You indicate that the values in the dictionary should be arrays, but it looks to me like eqClasses contains NSStrings (tempWordStr). Don't you need to create an NSArray to hold the NSStrings associated with a keyword and then make the array the value in the dictionary that corresponds to the keyword? If the dictionary already contains the key, you need to retrieve the array associated with the key, add the new string to the array, and then call setObject using the array with the key.

Resources