Getting length of an array inside a Dictionary Key - iphone

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.

Related

How to get the largest value from NSArray containing dictionaries?

How do you get the largest value from an NSArray with dictionaries?
Lets say I have NSArray containing dictionaries with keys "age", "name", etc.
Now I want to get the record with the highest age.
Is this possible with some KVC magic? Or do I have to iterate through and do it the "manual" way?
I've tried with something similar to this:
int max = [[numbers valueForKeyPath:#"#max.intValue"] intValue];
Unless "intValue" is a key in your dictionary the key path won't do much good.
If it is the max age you are after you should use #"#max.age" (on the dictionary) to get it. The same goes for any other key in your dictionary.
[myDictionary valueForKeyPath:#"#max.age"];
If numbers is an array of values you could use #"#max.self" as the key path to get the largest value.
[myArrayOfNumbers valueForKeyPath:#"#max.self"];
You're nearly there, you just need to specify the exact field you want from which you want the max value:
NSInteger max = [[numbers valueForKeyPath:#"#max.age"] integerValue];
I took the liberty to modify your ints to NSIntegers, just in case somebody wants to use this code on both iOS and OS X.

NSArray vs NSDictionary look up

Which is quicker and less expensive for checking if an object already exists within a list. By using the NSArray contains object or by checking if a key already exists for an NSDictionary?
Also does the NSArray containObject selecter iterate through the whole array elements? Also what about checking if a key already exists within a dictionary? Does that require iterating through all the keys.
Finally, what is the best and quickest way to check if an object already exists within a large list of objects (of the same class).
Thanks in advance
According to the document of Collection Classes the NSDictionary is based on HashTables. Which means if you are searching for a key in a dictionary, the time required is mush less than iterating through an array.
So, searching for a key should be o(1+numberofcollisions). where iterating through an array is o(n). You can quick sort array then binary search it which will make the cost a lot less. However for your buck, NSDictionary (hash table) are very cheap for searching.
From Apple docs
Internally, a dictionary uses a hash table to organize its storage and to provide rapid access to a value given the corresponding key. However, the methods defined for dictionaries insulate you from the complexities of working with hash tables, hashing functions, or the hashed value of keys. The methods take keys directly, not in their hashed form.
How many values are you talking about? The difference in speed may be irrelevant, thus making the choice be the one that makes the most sense in the code. In fact, that should probably be the first priority, unless and until you know that there is a speed problem.
Short version: Use NSDictionary unless you have a specific need not to.
I would say that the fastest way would be to sort your array when you insert an object:
NSMutableArray *myArray;
[myArray addObject:someCustomObject];
[myArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
// custom compare code here
}];
While this takes performance out of inserting an object, it would greatly increase your lookup times.
To do a binary search on a NSArray:
BOOL binarySearchContains(NSArray *sortedArray, id object, NSComparator comparisonBlock)
{
// simple recursive helper function
__block BOOL (^_binaryRecurse)(NSArray *, id, int lo, int hi) = ^BOOL(NSArray *array, id object, int lo, int hi)
{
int middleIndex = ((hi - lo) / 2) + lo;
if (hi == lo || middleIndex < 0 || middleIndex >= [array count])
return NO;
int compareResult = (comparisonBlock(object, [array objectAtIndex:middleIndex]));
if (compareResult < 0)
return _binaryRecurse(array, object, lo, middleIndex - 1);
if (compareResult > 0)
return _binaryRecurse(array, object, middleIndex + 1, hi);
return YES;
};
return _binaryRecurse(sortedArray, object, 0, [sortedArray count]);
}
In my tests, the bsearch is approximately 15 times faster than -containsObject:.

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.

Remove duplicates in NSdictionary

Is there a way to remove duplicate (key-value) pairs from NSDictionary ?
EDIT:
My description was misleading, I have duplicate pairs e.g.
key1-value1
key1-value1
key2-value2
key1-value1
etc..
reversing key-value is not good idea because not all values can be keys.
You can do it with:
// dict is original dictionary, newDict new dictionary withot duplicates.
NSMutableDictionary * newDict = [NSMutableDictionary dictionaryWithCapacity:[dict count]];
for(id item in [dict allValues]){
NSArray * keys = [dict allKeysForObject:item];
[newDict setObject:item forKey:[keys objectAtIndex:0]];
}
yuo can also use lastObject instead of objectAtIndex:0 to leave other key for dup objects
One way is to put the key/value pairs into a dictionary by value/key and then converting that back to key/value.
I can't think of a built-in method.
If you iterate over the values, allKeysForObject: will give you an array of keys for each value and if you have more more than one key, that value has duplicates.