Objective C: Create arrays from first array based on value - iphone

I have an array of strings that are comma separated such as:
Steve Jobs,12,CA
Fake Name,21,CA
Test Name,22,CA
Bill Gates,44,WA
Bill Nye,21,OR
I have those values in an NSScanner object so that I can loop through the values and get each comma seperated value using objectAtIndex.
So, what I would like to do, is group the array items into new arrays, based on a value, in this case, State. So, from those, I need to loop through, checking which state they are in, and push those into a new array, one array per state.
CA Array:
Steve Jobs,12,CA
Fake Name,21,CA
Test Name,22,CA
WA Array:
Bill Gates,44,WA
OR Array:
Bill Nye,21,OR
So in the end, I would have 3 new arrays, one for each state. Also, if there were additional states used in the first array, those should have new arrays created also.
Any help would be appreciated!

You can use a NSMutableDictionary of NSMutableArrays - if the state encountered isn't yet in the dictionary, add a new array.
NSMutableArray* arr = [states objectForKey:state];
if (arr == nil) {
arr = [NSMutableArray array];
[states setObject:arr forKey:state];
}
Then you can insert values into the array, preferably as objects though as Dave DeLong mentions.

You shouldn't be maintaining this data as CSV. That's asking for a world of hurt if you ever need to manipulate this data programmatically (such as what you're trying to do).
You can naïvely break this data up into an array using NSArray * portions = [line componentsSeparatedByString:#","];. Then create a custom object to store each portion (for an example, see this post), and then you can manipulate those objects almost effortlessly.

Naively: (assuming array of strings called strings)
NSMutableDictionary *states = [NSMutableDictionary dictionary];
for (NSString *string in strings) {
NSString *state = [[string componentsSeparatedByString:#", "] lastObject];
NSMutableArray *values = [states objectForKey:state];
if (values == nil) {
values = [NSMutableArray array];
[states setObject:value forKey:state];
}
[values addObject:string];
}
Number of things about this -- first of all, I'm not at my computer, so there is a high chance of typos and or things that I missed. Second, you probably want to adapt the components separated by string line to handle whitespace better.

Related

Sorting of NSMutableDictionary

Confusing !!!
I have one NSMutableDictionary called tempDict, having keys Freight, Fuel , Discount (and many more) with relevant values.
I am generating two different NSMutableArrays called arrTVBuyCharge and arrTVBuyCost from tempDict using this Code :
[arrTVBuyCharge addObjectsFromArray:[(NSArray *)[tempDict allKeys]]];
[arrTVBuyCost addObjectsFromArray:[(NSArray *)[tempDict allValues]]];
Problem : I want Freight, Fuel and Discount at the Top in the above arrays in same order (Ofcourse , with Ordering of Values).
What is the Optimum way to achieve this ?
It seems tricky at first, but it's simple when you think about it. All you want to do is get a sorted list of keys, and look up the value for each key as you add them to your arrays.
To get an array with the list of sorted keys:
NSArray *sortedKeys = [[tempDict allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
Then iterate through those and add them to NSMutableArrays:
NSMutableArray *arrTVBuyCharge = [[NSMutableArray alloc] init];
NSMutableArray *arrTVBuyCost = [[NSMutableArray alloc] init];
for (NSString *key in sortedKeys) {
[arrTVBuyCharge addObject:key];
[arrTVBuyCost addObject:[tempDict objectForKey:key]];
}
For even better performance, use the initWithCapacity method for the NSMutableArrays since you know the size.
This is the standard way of doing it.
1) Get three objects separately :
NSArray *mainKeys = #[#"Freight", #"Fuel", #"Discount"];
NSArray *mainValues = #[[tempDict valueForKey:#"Freight"],
[tempDict valueForKey:#"Fuel"],
[tempDict valueForKey:#"Discount"]
];
[arrTVBuyCharge addObjectsFromArray:mainKeys];
[arrTVBuyCost addObjectsFromArray:mainValues];
2) Remove them from tempDict :
[tempDict removeObjectsForKeys:mainKeys];
3) Add the objects from Updated tempDict :
[arrTVBuyCharge addObjectsFromArray:(NSArray *)[tempDict allKeys]];
[arrTVBuyCost addObjectsFromArray:(NSArray *)[tempDict allValues]];
This will make Freight, Fuel and Discount to be at index 0, 1 and 2 in your new Arrays.
Man, NSMutableDictionary always returns keys in a disordered fashion, if you really want to maintain order then you can sort it in alphabetical order or you can add 01, 02 ,03 serial numbers before your values to sort them in the order they were put it, later trim the first two characters of the string and use it.

[Xcode]How to count NSArray according to type

I would like to ask how could I count object type inside array. For example
this is my dataclass
+ (id)LocationWithID:(NSString *)UniqueID name:(NSString *)name address:(NSString *)address latitude:(float )latitude longitude:(float )longitude locationtype:(NSString *)locationtype country:(NSString *)country distance:(float )distance;
and this is my array
[array addObject:[dataclass LocationWithID:UniqueID name:name address:address latitude:latitude longitude:longitude locationtype:locationtype country:country distance:distance]];
and i would like to count how many country in this object. Normally we use
[array count];
but this will count all the object in the array. Now in my case i want to count non-repeated object for example i got an array contain 3 United kingdom, 5 USA, 7 Japan, 3 China and the result i want is country type = 4.
I would like to create several section for Table View according to the country type. Anyone?
You can use a dictionary to put objects with the same country in a separate array:
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
for (dataclass *location in array) {
if (![dictionary objectForKey:location.country]) {
[dictionary setObject:[NSMutableArray array] forKey:location.country];
}
[(NSMutableArray *)[dictionary objectForKey:location.country] addObject:location];
}
Now, not only you can get the number of different countries like this:
int countriesCount = [dictionary count];
But also, it is easy to populate each section of your table view with locations from the corresponding country.
You can retrieve all the locations for a specific country that has the name countryName, like this:
NSArray *locationsForCountry = [dictionary objectForKey:countryName];
You can also have the list of all the countries like this:
NSArray *countries = [[dictionary keyEnumerator] allObjects];
Enumerate each item in the array and for each item get the country and add it to an NSMutableSet. After enumeration, the size of the set is the number of unique countries.
There's probably a better way to do this if you're creating a table and you just want the table to have a section for each country, but I don't know it. I'd guess that it would be something like binding the appropriate properties in the table for creating sections to the right values in the array controller or on the array controller's elements.
NSArray doesn't have this functionality itself, so, as others have pointed out, it'd be easiest to keep a separate tally of counts for each country. The best way to do this would be to create an NSCountedSet object and add the countries to that as you add your data objects to the array.
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSCountedSet_Class/Reference/Reference.html
To get the count for any country, you just call [set countForObject:country]. Simple!

Getting length of an array inside a Dictionary Key

I'm sure this is a very obvious question but I'm not getting anywhere with it and I've been trying for half an hour or so now.
I have an NSMutableDictionary which has keys & values, obviously. Each key stores an array of objects. What I need to do is find a specific array in a key and get the list of the array. The catch is that I don't know the value of the key, I just know it's index. (EG: I know I need to find the array in the 2nd key).
I am almost certain this is a very easy & trivial thing to do but it's escaping me, I've only been doing Obj-C for a short while so not entirely at home with it yet!
Thanks,
Jack.
Use allKeys: to access the keys of your dictionary.
- (NSArray *)allKeys
Use as below .
NSArray* dictAllKeys = [dict allKeys];
if([dictAllKeys count] > 2)
{
NSArray* myArrayInDict = [dict objectForKey:[dictAllKeys objectAtIndex:1]];
// get the length of array in dict at 2nd key
int length = [myArrayInDict count];
}
The order will probably change if another key/value pair is added, it is a NSMutableDictionary. It is best not to rely on the order of a NSDictionary or NSSet.
Suggestion: Either use another container that does provide ordering such as NSMutableArray or find the item using the dictionary's value arrays, perhaps with NSPredicate.

Objective-C, How can I produce an array / list of strings and count for each?

My aim is to produce an array, which I can use to add section headers for a UITableView. I think the easiest way to do this, is to produce a sections array.
I want to create section headers for dates, where I'll have several or no rows for each.
So in my populate data array function, I want to populate a display array. So record 1, look for the first date in my display array, create a new array item if it doesn't exist, if it does exist add 1 to the count.
So I should end up with something like this.
arrDisplay(0).description = 1/June/2001; arrDisplay(0).value = 3;
arrDisplay(1).description = 2/June/2001; arrDisplay(1).value = 0;
arrDisplay(2).description = 3/June/2001; arrDisplay(2).value = 1;
arrDisplay(3).description = 5/June/2001; arrDisplay(3).value = 6;
My question is how do I create and use such an array with values, where I can add new elements of add to the count of existing elements and search for existing elements ?
I think, if i understand you, an NSMutableDictionary would work. (as NR4TR said) but, i think the object would be the description and the key would be the count. you could check for the key and get the count in the same gesture. if the return value of objectForKey is nil, it doesn't exist.
NSMutableDictionary *tableDictionary = [[NSMutableDictionary alloc] init];
NSString *displayKey = #"1/June/2001";
NSNumber *displayCount = [tableDictionary objectForKey:displayKey];
if (displayCount != nil) {
NSNumber *incrementedCount = [[NSNumber alloc] initWithInteger:[displayCount integerValue] + 1];
[tableDictionary removeObjectForKey:displayKey];
[tableDictionary setValue:incrementedCount
forKey:displayKey];
[incrementedCount release];
}
else {
NSNumber *initialCount = [[NSNumber alloc] initWithInteger:1];
[tableDictionary setValue:initialCount
forKey:displayKey];
[initialCount release];
}
EDIT: Hopefully this isn't pedantic, but I think a couple pointers will help.
Dictionaries, Sets, and Arrays all hold objects for retrieval. The manner of holding and retrieval desired drives the decision. I think of it based on the question 'what is the nature of the information that I have when I need an object being held?'
NSDictionary and NSMutableDictionary
Hold n objects per key. (I think...I haven't had to test a limit, but i know you can get an NSSet back as a value.)
KEY is more important than INDEX. I don't think of dictionaries as ordered. they know something and you need to ask the correct question.
NSArray and NSMutableArray
hold n objects in order.
INDEX is most important bit of information. (you can ask for the index of an object but, even here, the index is the important part)
you will typically drive table views with an array because the ordered nature of the array fits.
NSSet, NSMutableSet, and NSCountedSet
A collection of objects without order.
You can change any of these into the other with something like [nsset setFromArray:myArray];
and all of these things can hold the other as objects. I think an array as your top level is the correct thinking, but beyond that, it becomes an issue of implementation
Try array of dictionaries. Each dictionary contains two objects - section title and array of section rows.
If you want to have a description AND a rowcount then you can either create a class with those two properties and generate an NSArray of objects with that class or instead of all that you can just use an NSDictionary to store key/value lookups.
I think NSCountedSet is closest to what you want. It doesn't have an intrinsic order, but you can get an array out of it by providing a sort order.

NSDictionary split into two arrays (objects and keys) and then sorted both by the objects array (or a similar solution)

I have an NSDictionary. It has keys and objects.
For the purposes of simplicity the keys are Question numbers and the objects are calculated Answer scores.
Now how I did it before was that I set the answer score as the keys and the question numbers as the objects. This way I could get an array of allKeys from the dictionary, sort it and then do something similar to:
for(NSString *string in tempArray){
NSLog(#"%#",[dictionary objectForKey:string]);
}
The (stupid - on my part) problem that I have now encountered however is that (obviously... duuhhh) the keys need to unique, and therefore when the calculated answer scores are the same, only one answer gets output!
I need a solution to this. In PHP you can multisort arrays. I was wondering if there was some similar solution in objective-c or indeed if someone had a better answer?
Any help here would be much appreciated.
Thank you.
Do you know about the allKeys, allValues and allKeysForObject method of the NSDictionary do you ?
One solution is to store the answer scores using an array of dictionaries containing only two key-value pairs. One key is the question number (or however your questions are tagged, i.e. “Q1.1”), while the other key is the actual answer score. For example:
static NSString * const QuestionKey = #"questionNumber";
static NSString * const AnswerScoreKey = #"answerScore";
NSMutableArray *allAnswers = [NSMutableArray array];
for (int i = 0; i < 20; i++)
{
// fill allAnswers array with random data
NSDictionary *answer = [NSDictionary dictionaryWithObjectsForKeys:
[NSString stringWithFormat:#"Q%d", i], QuestionKey,
[NSNumber numberWithInt:rand()], AnswerScoreKey,
nil];
[allAnswers addObject:answer];
}
// sort the allAnswers array based on score, highest first
NSSortDescriptor *sortDesc = [NSSortDescriptor sortDescriptorWithKey:AnswerScoreKey ascending:NO];
[allAnswers sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
for (NSDictionary *answer in allAnswers)
{
NSLog(#"Question: %#, AnswerScore: %#", [answer objectForKey:QuestionKey], [answer objectForKey:AnswerScoreKey];
}
Disclaimer:
Untested and uncompiled code. Theory only.
I am not sure what you are actually trying to achieve. Do you want to sort an array of dictionary objects based on the value of the dictionary? If that is what you want, you can define your own comparator function and can define any custom sorting behavior. Please check sortedArrayUsingSelector: method of NSArray.
Edit : I am away from Mac currently but this previous question has a number of example code that can solve your problem. Rather than using object, you can use NSDictionary, though personally I would like to use another Question object instead of dictionary in this case. This question class will contain two value, id and score and then you need to sort the array of questions based on score just like the persons are sorted based on birthday.