What I am trying to do is create a an array of text strings, and I want to select a random text string out of this array, which I could normally do easily with an array. However, I would also like to be able to put them into categories, and when I select a random one, I would like to know what category it is in and do something different with it which is decided by the category it was in. I was thinking I could use keys in NSDictionary to decide the categories as in setting all the entries in a category to have the same key. But then I don't know how I could retrieve a random one from that dictionary and then know what the key was. I have never used NSDictionary so I don't know much about it so maybe what I just said doesn't make any sense.
It is also possible that I am approaching this in completely the wrong way, so if you have any other suggestions as to how to do what I described I would be open to that, and a pretty detailed code answer would be best if it is possible.
I would just fill the array with dictionaries, i.e.
{
{ category = Animals,
name = Cat },
{ category = Vehicles,
name = Helicopter },
{ category = Foods
name = Pie },
{ category = Animals,
name = Zebra }
}
and then select randomly from that array.
For a programmatic example:
theArray = [NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:#"Animals", #"category", #"Cat", #"name", nil],
[NSDictionary dictionaryWithObjectsAndKeys:#"Vehicles", #"category", #"Helicopter", #"name", nil],
// ...
[NSDictionary dictionaryWithObjectsAndKeys:#"Animals", #"category", #"Zebra", #"name", nil],
nil];
// ...
randomDict = [theArray objectAtIndex:(rand() % [theArray count])];
NSString *name = [randomDict objectForKey:#"name"];
NSString *category = [randomDict objectForKey:#"category"];
Related
I have an NSMutableArray of elements and I want to be able to conditionally set custom flags for some of the elements. For example an error count for certain elements if they return an error. If the count is more than 3, I would like to delete this element from an array.
What would be the best way to implement such behaviour?
A few options:
Have a separate array holding your counter for each object. When deleting one from your original array, remember to delete it's corresponding counter object.
Create a small class that contains an int value and whatever other object you are storing in the array, and populate your NSMutableArray with that object. You will then have your object and the error counter on the same place
Edit: The second option is the most scalable one, if you ever want to add more flags or whatever to it.
You would be better off creating a mutable array filled with mutable dictionaries. This would allow you have two keys corresponding to each index in the array:
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"some text, or what ever you want to store",#"body",
[NSNumber numberWithUnsignedInteger:0],#"errorCount",
nil];
[myMutableArray addObject:mutableDictionary];
And then here is a basic example of how to increment the error count for a specific item in the array:
- (void)errorInArray:(NSUInteger)idx
{
if ([[[myMutableArray objectAtIndex:idx] objectForKey:#"errorCount"] unsignedIntegerValue] == 2) {
[myMutableArray removeObjectAtIndex:idx];
}else{
NSUInteger temp = [[[myMutableArray objectAtIndex:idx] objectForKey:#"errorCount"] unsignedIntegerValue];
temp ++;
[[myMutableArray objectAtIndex:idx] setObject:[NSNumber numberWithUnsignedInteger:temp] forKey:#"errorCount"];
}
}
As alluded above, no need for custom object creation necessarily:
Creating a mutable array, creating a dictionary with objects/keys and adding said dictionary to the array:
NSMutableArray *myArray = [[NSMutableArray alloc] init] autorelease];
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"John Doe", #"elementName",
[NSNumber numberWithInt:0], #"errorCount",
nil];
[myArray addObject:myDictionary];
I have a main NSMutableDictionary that contains a collection of others NSMutableDictionary.
The thing goes like this:
NSMutableDictionary *subDict1 = [NSMutableDictionary dictionaryWithObjectsAndKeys:
obj1, #"name",
obj2, #"color",
nil];
NSMutableDictionary *subDict2 = [NSMutableDictionary dictionaryWithObjectsAndKeys:
obj3, #"name",
obj4, #"color",
obj5, #"address",
obj6, #"phone",
obj7, #"color",
obj8, #"parent",
nil];
NSMutableDictionary *subDict3 = [NSMutableDictionary dictionaryWithObjectsAndKeys:
obj0, #"name",
obj9, #"parent",
objA, #"site",
objB, #"surname",
objC, #"label",
nil];
These sub dictionaries may have different number of entries and the keys may vary. Some may have keys with the same name.
They are stored in a main dictionary like this:
NSMutableDictionary *mainDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
subDict1, #"1",
subDict3, #"3",
subDict2, #"2",
nil];
I want at one shot, remove all entries in all sub dictionaries that have a specific key.
I know I can iterate thru the dictionaries and sub dictionaries, but I also know that Dictionaries have smart ways to do that using predicates and other stuff, but I am not seeing how. I am trying to find that because the method this will run is a little bit tricky and have to do it as fast as possible and I am not sure if normal iteration with loops or whatever will be fast enough...
Any clues? thanks.
Here's a recursive method that doesn't care how many levels deep the target key is. (haven't tried it) ...
- (void)removeKey:(NSString *)keyToRemove fromDictionary:(NSMutableDictionary *)dictionary {
NSArray *keys = [dictionary allKeys];
if ([keys containsObject:keyToRemove]) {
[dictionary removeObjectForKey:keyToRemove];
} else {
for (NSString *key in keys) {
id value = [dictionary valueForKey:key];
if ([value isKindOfClass:[NSMutableDictionary self]]) {
[self removeKey:keyToRemove fromDictionary:(NSMutableDictionary *)value];
}
}
}
}
You'll need to just iterate through all the subdirectories and remove the appropriate key-value pairs manually. You shouldn't worry if it's fast enough at this point. Rather, create a working implementation and test/measure it. If it's too slow, then you can profile it and come up with ways to improve performance. Premature optimization is a bad thing.
NSArray* keys = [NSArray arrayWithObjects:#"name", #"address", nil];
[dics removeObjectsForKeys:keys]; //Or sub dics
I am making an app. where i want to add vendor name and it's device name..
I am using a dictionary where vendor name is key and device name are values..
Here is my code
[appDelegate.arrOfDevice addObject:txtDeviceName.text];
[appDelegate.dictOfDetails setObject:appDelegate.arrOfDevice forKey:txtVendorName.text ];
Here arrOfDevice is an array(declared in appdelegate) which is having all devices which are added..
I want to add devices based on particular keys...
I know, i am doing something wrong,
I am pushing the array as values in dictionary so it will store all the device names for each key.. but please help me...So that i could store device names based on particular key...
If u are not able to understand please fell free to get clarification of my question...
If you are adding key for the first time then you need to do this as shown below
if(flag==1) {
NSMutableArray *tmpArr=[[NSMutableArray alloc]init];
[tmpArr addObject:txtDeviceName.text];
[appDelegate.dictOfDetails setObject:tmpArr forKey:[txtVendorName.text uppercaseString]];
}
and if the key is present you just need to create a reference for an array and add object to the dictionary
else if(flag==0) {
NSMutableArray *arrDevice=[appDelegate.dictOfDetails objectForKey:[txtVendorName.text uppercaseString]];
[arrDevice addObject:txtDeviceName.text] ;
}
NSDictionary *dic = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"Nit",[NSNumber numberWithInt:3],nil]
forKeys:[NSArray arrayWithObjects:#"Name",#"num",nil]];
>>Edited
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:
#"value1", #"key1", #"value2", #"key2", nil];
also seem +dictionaryWithObjects:forKeys:
Hope, this will help you...
Currently I'm programming an app with a tableView, similar to that one in the iPhone Contacts app.
Everything works (the sections, the bar on the right showing the titles, the cells are configured...), beside the search bar. I'm familiar how to do this (search) if the tableView's data is loaded from an array, but my situation is that its loaded from arrays located in a NSDictionary.
The dict looks like
Key = "A" >> Value = "array = apple, animal, alphabet, abc ..."
Key = "B" >> Value = "array = bat, ball, banana ..."
How can I remove all strings (from all of the dictionary's arrays) matching the search term?
Thanks a lot in advance :)
Well you can do it like this
NSMutableDictionary *newItems = [NSMutableDictionary dictionary];
for (NSString *key in oldItems) {
NSMutableArray *newArray = [NSMutableArray array];
for (NSString *item in [oldItems objectForKey:key]) {
if ([item rangeOfString:searchTerm].location != NSNotFound) {
[newArray addObject:item];
}
}
if ([newArray count]) {
[newItems setObject:newArray forKey:key];
}
}
[oldItems release];
oldItems = [newItems retain];
I don't know if this is the best way to do it or even if it's faster enough but let me know if this works for you.
Did you want to update the existing Dictionary with the new Array that excludes that string?
NSMutableDictionary* excludedDictionary = [NSMutableDictionary dictionaryWithDictionary:existingDictionary];
for(id key in [existingDictionary allKeys])
{
NSArray* existingArray = [existingDictionary objectForKey:key];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"self != %#", excludedString];
NSArray* excludedArray = [existingArray filteredArrayUsingPredicate:predicate];
[excludedDictionary setObject:excludedArray forKey:key];
}
existingDictionary = [NSDictionary dictionaryWithDictionary:excludedDictionary];
This will replace your existing dictionary with one that doesn't have the string in it...
From you comments, I understand that you want to filter the table contents on the basis of what the user enters in the text field. For this, you do not need to modify your dictionary at every character change. The UISearchDisplayController is provided for exactly this scenario. Have a look at the reference for details: http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UISearchDisplayController_Class/Reference/Reference.html.
HTH,
Akshay
This one is a bit tedious in as far as explaining, so here goes. I'm essentially populating a tableView on the iPhone with multiple sections, and potentially multiple rows per section. To my understanding, it's best to have an array of arrays so that you can simply determine how many sections one has by sending a message to the top level array of count, then for rows per section, doing the same for the inner array(s). My data is in the form of a dictionary. One of the key/value pairs in the dictionary determines where it will be displayed on the tableView. An example is the following:
{
name: "bob",
location: 3
}
{
name: "jane",
location: 50
}
{
name: "chris",
location: 3
}
In this case I'd have an array with two subarrays. The first subarray would have two dictionaries containing bob and chris since they're both part of location 3. The second subarray would contain jane, since she is in location 50. What's my best bet in Cocoa populate this data structure? A hash table in C would probably do the trick, but I'd rather use the classes available in Cocoa.
Thanks and please let me know if I need to further clarify.
The following code works: (edit: added my initialization code)
NSArray * arrayOfRecords = [NSArray arrayWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:
#"bob", #"name",
[NSNumber numberWithInt:3], #"location", nil],
[NSDictionary dictionaryWithObjectsAndKeys:
#"jane", #"name",
[NSNumber numberWithInt:50], #"location", nil],
[NSDictionary dictionaryWithObjectsAndKeys:
#"chris", #"name",
[NSNumber numberWithInt:3], #"location", nil],
nil];
NSMutableDictionary * sections = [NSMutableDictionary dictionary];
for (NSDictionary * record in arrayOfRecords)
{
id key = [record valueForKey:#"location"];
NSMutableArray * rows = [sections objectForKey:key];
if (rows == nil)
{
[sections setObject:[NSMutableArray arrayWithObject:record] forKey:key];
}
else
{
[rows addObject:record];
}
}
NSArray * sortedKeys = [[sections allKeys] sortedArrayUsingSelector:#selector(compare:)];
NSArray * sortedSections = [sections objectsForKeys:sortedKeys notFoundMarker:#""];
NSLog(#"%#", sortedSections);
And NSDictionary is a hash table.
In Cocoa, it's best to use model objects rather than primitive collections, especially when using Bindings. The dictionaries should certainly be model object, and you may want to turn your inner arrays into model objects as well. (The outer array should stay an array.)
Cocoa Touch doesn't have Bindings, but I find (in Cocoa, as I don't program my iPhone) that model objects make things easier to think about and work with. I recommend you make model objects anyway.
(“Model” refers to Cocoa's “Model-View-Controller” pattern, in which Cocoa provides view and controller objects and you provide the model.)