Looping thru NSArray of NSString logic - ios

I need help with the following:
I have an NSArray with NSStrings, I want to loop thru these strings and find a matching string, when match is found the strings after this match will be extracted into an NSDictionary until a certain other match is hit.
Here is an example:
NSArray *array = #[#"Fruit",#"Apple",#"Vegtable",#"Tomato",#"Fruit",#"Banana",#"Vegtable",#"Cucumber"];
So I want to loop thru this array and split it in 2 arrays one for fruit and one for vegetable.
Anyone can help with the logic?
Thanks

This is probably the simplest way to solve the problem:
NSArray *array = #[#"Chair",#"Fruit",#"Apple",#"Orange",#"Vegetable",#"Tomato",#"Fruit",#"Banana",#"Vegetable",#"Cucumber"];
NSMutableArray *fruitArray = [NSMutableArray array];
NSMutableArray *vegetableArray = [NSMutableArray array];
NSMutableArray *currentTarget = nil;
for (NSString *item in array)
{
if ([item isEqualToString: #"Fruit"])
{
currentTarget = fruitArray;
}
else if ([item isEqualToString: #"Vegetable"])
{
currentTarget = vegetableArray;
}
else
{
[currentTarget addObject: item];
}
}
In one iteration over the array, you just keep adding items to a result array using a pointer to one of two result arrays according to the last occurrence of the #"Fruit" or #"Vegetable" string.
This algorithm ignores all items before the first occurrence of the #"Fruit" or #"Vegetable" string, because the currentTarget is initialized to nil, which ignores the addObject: messages. If you want different behaviour, just change the initialization.
You said you wanted the results in a NSDictionary, but didn't specify what should be the key. If you want one NSDictionary with two keys, Fruit and Vegetable, and values NSArrays containing the items, just use the arrays previously created:
NSDictionary *dict = #{ #"Fruit": fruitArray, #"Vegetable": vegetableArray };
PS: You have a typo in your example, Vegtable instead of Vegetable. I corrected it in my code, so keep it in mind.

If I completely understand you:
NSArray *array = #[#"Fruit",#"Apple",#"Vegtable",#"Tomato",#"Fruit",#"Banana",#"Vegtable",#"Cucumber"];
NSMutableArray *fruits = [NSMutableArray array];
NSMutableArray *vegtables = [NSMutableArray array];
for (NSInteger i = 0; i < array.count; ++i){
if ([array[i] isEqualToString:#"Fruit"]){
++i;
[fruits addObject:array[i]];
}
else if ([array[i] isEqualToString:#"Vegtable"]){
++i;
[vegtables addObject:array[i]];
}
}

Related

Dictionary allKeys vs keyEnumerator?

Which to use when?
What if I am looping the dictionary and removing key-values from it, will the enumerator work for that? Documentation seem to answered that question:
If you use this method with instances of mutable subclasses of
NSDictionary, your code should not modify the entries during
enumeration. If you intend to modify the entries, use the allKeys
property to create a “snapshot” of the dictionary’s keys. Then use
this snapshot to traverse the entries, modifying them along the way.
Performance?, because people always want to know.
Iteration through NSDictionary could be achieved at least in two ways: using NSArray with [NSDictionary allKeys] or NSEnumerator.
NSArray *keyArray =  [bigUglyDictionary allKeys];
int count = [keyArray count];
for (int i=0; i < count; i++) {
  NSDictionary *tmp = [bigUglyDictionary objectForKey:[ keyArray objectAtIndex:i]];
}
NSEnumerator *enumerator = [bigUglyDictionary keyEnumerator];
id key;
while ((key = [enumerator nextObject])) {
NSDictionary *tmp = [bigUglyDictionary objectForKey:key];
}
Second way is a little bit faster, so if you work with huge dictionaries and have no need of array with their keys

Objective-C: Remove duplicates efficiently from large data structures

I have an object containing an array of NSNumbers (indexes) and an array of NSDictionaries (indexesTitles) corresponding to indexes, containing some info.
I have to call a method for each object.index and associate object.indexTitles to the returning results, saving them into a single array.
At the end of it, I want to remove indexes duplicates, preserving the associated indextTitles in an efficient way, because I'm working with large arrays.
NSMutableArray *resultArray = [NSMutableArray array];
NSMutableArray *titlesArray = [NSMutableArray array];
for(NSNumber *index in object.indexes)
{
NSArray *resultsIndexArray = [self methodThatReturnsAnArray];
NSString *indexTitleDictionary = [object.indexesTitles objectAtIndex:i];
for(NSNumber *resultId in resultsIndexArray)
{
[titlesArray addObject:indexDictionary];
[resultArray addObject:resultId];
}
i++;
}
[fullResultsArray addObject:titlesArray];
[fullResultsArray addObject:resultArray];
I've found that the most efficient way to remove duplicates is using an
NSOrderedSet like this:
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:resultArray];
resultArray = [orderedSet.array mutableCopy];
How can I remove the corresponding entries in titlesArray? how can I preserve the association?
I've also tried to use a NSDictionary like {resultId, titleDictionary} and storing them into an array, but I haven't found a efficient way to remove dictionaries with the same result, they are all too slow.
Any suggestion?
It is not completely clear to me what your problem is, maybe this will help:
A good way to remove duplicates is not to add them in the first place, replace:
for(NSNumber *resultId in resultsIndexArray)
{
[titlesArray addObject:indexDictionary];
[resultArray addObject:resultId];
}
with:
for(NSNumber *resultId in resultsIndexArray)
{
// only add if resultId not already in resultArray
if( ![resultArray containsObject:resultId] )
{
[titlesArray addObject:indexDictionary];
[resultArray addObject:resultId];
}
}
The containsObject: call requires a linear search, if your data set is large you might wish to change resultArray to an NSMutableSet and titlesArray to an NSMutableDictionary mapping from resultId to indexDictionary values.
HTH

Multi dimensional array containing array of dictionaries

Trough my ios first app developpement i have to re-order an array containing dictionaires, parsed from a xml document, the purpose of re-ordering it is to send it to a function that build a collapsible, so it need a childCell index and a parentCell Index to print the strings of each child then pass to another parent. The problem is here : i'am able to fill my big array containing arrays of dictionaries, then i that array and do a loop to fill the childArray to contain multiple dictionaries, then i add this child array to my parent array, every thing seem to run but it gives me an empty array at the end. i put my code to show you how i tried to do this :
stories is the NSArray of dictionaries, childArray is the Array that should contain the dictionaries of stories, and parentArray is the Array that contains it all.
If someone who already did that can explain me were it goes wrong please it would be very much appreciated.
-(NSMutableArray *)orderChildsAndParents:(NSMutableArray *)fromArray
{
int varial = 0;
int catIndex = 0;
NSMutableArray *parentArray = [NSMutableArray array];
while(varial < [stories count])
{
NSString* cleanedString = [[[[stories objectAtIndex:varial] objectForKey:#"category"] componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
componentsJoinedByString:#""];
if ([cleanedString isEqualToString:[category objectAtIndex:catIndex] ])
{
if (!childArray || !childArray.count)
childArray = [NSMutableArray array];
[childArray addObject:[stories objectAtIndex:varial]];
varial++;
}
else{
[parentArray addObject:childArray];
[childArray removeAllObjects];
catIndex++;
}
}
NSLog(#"%#", parentArray);
return parentArray;
}
- (NSString *) labelForCellAtChildIndex:(NSInteger) childIndex withinParentCellIndex:(NSInteger) parentIndex {
NSMutableArray *orderedArray = [self orderChildsAndParents:stories];
NSLog(#"format string %#", [[[orderedArray objectAtIndex:parentIndex] objectAtIndex:childIndex] objectForKey:#"name"]); // empty :8
return [[[orderedArray objectAtIndex:parentIndex] objectAtIndex:childIndex] objectForKey:#"name"];
}

Sort an NSArray by another nsarray with ids

i have 2 nsarrays
1 with nsdictionary's another with nsnumbers
NSArray *arr1 = #[#{#"id":#1},#{#"id":#2},#{#"id":#3},#{#"id":#4}];
NSArray *arr2 = #[#3,#1,#4,#2];
and i want to sort my arr1 through their id following the order of arr2
is this possible?
The problem with using sortedArrayUsingComparator: is you start dealing with O(n^2) lookup times. For each sort comparison in the first array, you have to do a lookup in the second array.
Your best bet is to take advantage of a hash table to reduce that to O(n) average complexity.
Your first step is to create a dictionary using id as a key. The result would look something like #{#1: #{#"id":#"1"}, ...}. Then you just have to construct an array by looping through arr3 and grabbing the values.
NSArray *arr1 = #[#{#"id":#1},#{#"id":#2},#{#"id":#3},#{#"id":#4}];
NSArray *arr2 = #[#3,#1,#4,#2];
NSMutableDictionary *map = [NSMutableDictionary dictionary];
for (NSDictionary *item in arr1) {
map[item[#"id"]] = item;
}
NSMutableArray *arr3 = [NSMutableArray array];
for (id key in arr2) {
[arr3 addObject:map[key]];
}
This solution of course assumes parity between the two arrays. If arr2 has an element not in arr1 it will crash when trying to add nil to arr3. If arr1 has a value not in arr2 it will be excluded from arr3. These are risks you will have to address based on your requirements.
Here is how you can do it by using a custom comparator:
NSArray* sorted= [arr1 sortedArrayUsingComparator: ^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) {
return [arr2 indexOfObject:obj1[#"id"]] - [arr2 indexOfObject:[obj2[#"id"]];
}];
I exploited the fact that NSComparisonResult has +1 to represent an ascending order, -1 for descending and 0 to represent the same order.
- (NSArray*) sortedArray
{
NSArray *arr1 = #[#{#"id":#1},#{#"id":#2},#{#"id":#3},#{#"id":#4}];
NSArray *arr2 = #[#3,#1,#4,#2];
NSMutableArray *mutableArray = [NSMutableArray new];
for (NSNumber *number in arr2)
{
for (NSDictionary* dictionary in arr1)
{
NSNumber *number2 = dictionary[#"id"];
if ([number isEqual:number2])
{
[mutableArray addObject:dictionary];
break;
}
}
}
return mutableArray;
}

NSMutableDictionary -- using allKeysforObject not retrieving array values

NSMutableDictionary *expense_ArrContents = [[NSMutableDictionary alloc]init];
for (int i = 1; i<=4; i++) {
NSMutableArray *current_row = [NSMutableArray arrayWithObjects:#"payer_id",#"Expense_Type_id",#"Category_Id",#"SubCategory_Id",nil];
[expense_ArrContents setObject:current_row forKey: [NSNumber numberWithInt:i]];
}
NSArray *newArray = [expense_ArrContents allKeysForObject:#"payer_id"];
NSLog(#"%#",[newArray description]);
i want to get the list of key values containing the particular object which is in the array of values stored in nsmutabledictionary for a particular key.
In the line where you get all the keys ([expense_ArrContents allKeysForObject:#"payer_id"];) you actually get keys for an object that is not in any of the array's items. This #"player_id" is different object than the #"player_id" you added in current_row. In fact, maybe all of your rows have different #"player_id" objects (except if the compiler has made some optimization - maybe it threats that same string literal as one object instead of creating new object for each iteration).
Try creating an NSString object for the #"player_id" which you add to the current_row and then get all the keys for that same object:
NSString* playerId = #"player_id";
for(){
NSMutableArray *current_row = [NSMutableArray arrayWithObjects: playerId,...];
...
}
NSArray *newArray = [expense_ArrContents allKeysForObject:playerId];
Your NSArray *newArray = [expense_ArrContents allKeysForObject:#"payer_id"]; will not return any value because in expense_ArrContents there is no such key(#"payer_id"), instead there are keys like 1,2,3 etc.What is your requirement?Want to see what all keys are there in expense_ArrContents just log
NSArray*keys=[expense_ArrContents allKeys];
Try this :
NSMutableArray *array_key=[[NSMutableArray alloc]init];
for (NSString *key in expense_ArrContents) {
if ([[expense_ArrContents objectForKey:key] containsObject:#"payer_id"]) {
[array_key addObject:key];
}
}

Resources