Increment count of duplicate NSDictionary objects in an NSArray? - iphone

I am writing a shopping cart application where I have Item Information sent back from server as a NSDictionary object with item number,description,price as values for their keys. I add all these Dictionary objects to mutable array and display in a table view. To manually increment quantity of each item I have added Quantity key to Item Dictionary object.
NSMutableDictionary* itemDictionary = [[NSMutableDictionary alloc] initWithDictionary:inventory.itemDict];
[itemDictionary setObject:[NSString stringWithFormat:#"1"] forKey:#"Quantity"];
[itemsArray addObject:itemDictionary];
[itemDictionary release];
[self.tableView reloadData];
How to increment value for key Quantity if there is a duplicate entry of the same item ? If I add same item to array I would end up with a duplicate, How to find duplicate item i.e., item that has same price, description and item number while ignoring value of Quantity key of the dictionary when searching for duplicates

I would create a new dict containing two items: the inventory dict and the quantity. I'd add an item to itemsArray like this (untested, so beware of typos):
BOOL found = NO;
for (NSDictionary *dict in itemsArray)
{
if ([[dict objectForKey: #"inventorydict"] isEqual: inventory.itemDict])
{
[dict setObject: [NSNumber numberWithInt:
[[dict objectForKey: #"quantity"] intValue] + 1]
forKey: #"quantity"];
found = YES;
break;
}
}
if (!found)
{
[itemsArray addObject:
[NSMutableDictionary dictionaryWithObjectsAndKeys:
inventory.itemDict, #"inventorydict",
[NSNumber numberWithInt: 1], #"quantity",
nil]];
}
So itemsArray contains NSDictionaries with two keys: "inventorydict" and "quantity". "inventorydict" is the dict passed to you containing the item the user bought, and "quantity" is an NSNumber. When you receive a new product item in the basket, you first check if the item is already in the array. If so, you add one to the "quantity" number, otherwise you create a new dictionary with the inventory item and a quantity of 1.

Store your dictionaries in an NSCountedSet. You can then get the quantity via -countForObject:. Use an array only for presentation purposes, so you can sort the values in a sane way. Rebuild this array whenever the set changes, something like so:
- (void)itemsDidChange
{
NSCountedSet *itemSet = [self itemSet];
NSMutableArray *sortedItems = [[NSMutableArray alloc] init];
for (NSDictionary *item in itemSet) {
NSUInteger count = [itemSet countForObject:item];
NSNumber *countNum = [[NSNumber alloc] initWithUnsignedInteger:count];
NSMutableDictionary *arrayItem = [item mutableCopy];
[arrayItem setObject:countNum forKey:KEY_QUANTITY];
[countNum release];
[sortedItems addObject:arrayItem];
[arrayItem release];
}
[sortedItems sortUsingComparator:/* your comparator here */];
[self setRowItems:sortedItems];
[[self tableView] reloadData];
}
Even simpler, use the object directly in your array without changing it at all. When you present the quantity to the user in the UI, just query the itemSet for the count, and use that. The array is then used solely to impose an order on the set's items.

FYI for setObject: you do not need to use stringWithFormat: if you do not have an object to add to it, you can simply use setObject:#"1".
If you want to increment the Quantity, you should be using setObject:[NSNumber numberWithInt:1] instead.

based on Rudy's post made it working this way:
-(void)addToCart:(id)sender
{
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
BOOL found = NO;
NSString *itemName = // get your item name here
[theDict setObject:itemName forKey:#"name"];
if ([appDelegate.theCartArray isEqual:nil])
{
[appDelegate.theCartArray addObject:theDict];
}
else //implementing Rudy's idea
{
for (theDict in appDelegate.theCartArray)
{
if ([[theDict objectForKey:#"name"] isEqual:itemName])
{
[theDict setObject: [NSNumber numberWithInt:
[[theDict objectForKey: #"quantity"] intValue] + 1]
forKey: #"quantity"];
found = YES;
break;
}
}
if (!found)
{
[appDelegate.theCartArray addObject:
[NSMutableDictionary dictionaryWithObjectsAndKeys:
itemName, #"name",
[NSNumber numberWithInt: 1], #"quantity",
nil]];
}
}
}

Related

Using FlurryAnalytics logEvent:withParameters

When a user enters a search query, I'd like to track:
1) Their search term
2) Number of results returned
3) CFUUID
Can someone tell me if all of these parameters can be put into 1 Dictionary or do I need to create a separate Dictionary for every key/value?
Can I do this:
NSDictionary *flurryDict =
[NSDictionary dictionaryWithObjectsAndKeys:searchText,#"Search Term",numResults,#"Results Returned",nil];
[FlurryAnalytics logEvent:#"USER_SEARCH" withParameters:flurryDict];
Here's what I have so far:
//View Controller
if([searchText length] >=3){
NSLog(#"Search: %#",searchText);
NSLog(#"Search Results: %i",[self.filteredListContent count]);
NSLog(#"Device UUID: %#",[sharedLabelManager myUUID]);
//Send to Flurry
NSDictionary *flurryDict =
[NSDictionary dictionaryWithObjectsAndKeys:#"Search Term", searchText, nil];
[FlurryAnalytics logEvent:#"SEARCH" withParameters:flurryDict];
}
Yep. Dictionaries are a set of keys and values, something like below will work just fine:
NSString *uuid = [sharedLabelManaged myUUID];
NSNumber *totalResults = [NSNumber numberWithInt:self.filteredListContent.count];
NSDictionary *flurryDict = [NSDictionary dictionaryWithObjectsAndKeys:searchText, #"SearchTerm", totalResults, #"SearchResultsCount", uuid, #"UUID", nil];
[FlurryAnalytics logEvent:#"SEARCH" withParameters:flurryDict];

How to add the object array to nsmutabledictionary with another array as key

for(Attribute* attribute in appDelegate.attributeArray) {
attribute = [appDelegate.attributeArray objectAtIndex:z];
attri = attribute.zName;
int y = 0;
for(Row* r in appDelegate.elementsArray) {
r = [appDelegate.elementsArray objectAtIndex:y];
NSString *ele = r.language;
if([attri isEqualToString:ele]) {
NSLog(#"=================+++++++++++++++++%# %#",attri, r.user);
[aaa insertObject:r atIndex:y]; //here i am adding the value to array
[dict setObject:aaa forKey:attri]; //here i am adding the array to dictionary
}
y++;
}
z++;
NSLog(#"============$$$$$$$$$$$$$$$$$$$$$$$++++++++++ %#",dict);
}
key in one array and the value in the another array and the value array is in object format.
I need to store the multi object for the single key. The attributeArray has the key value and the elementsArray has the object. For example the attributeArray might have the values
" English, French, German..."
and the elementsArray might have the object value
"<Row: 0x4b29d40>, <Row: 0x4b497a0>, <Row: 0x4e38940>, <Row: 0x4b2a070>, <Row: 0x4b29ab0>, <Row: 0x4b178a0> "
In the first value I need to store the two object and for second key I need to store 3 objects and for the third key in need to store last two objects in the dictionary.
For super-simplification you can use the following code:
NSArray *keys = ...;
NSArray *values = ...;
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjects: values forKeys: keys];
Hope, this helps.
UPDATE:
to store multiple values for single key in the dictionary, just use NSArray / NSMutableArray as your object:
NSArray *keys = ...;
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for( id theKey in keys)
{
NSMutableArray *item = [NSMutableArray array];
[item addObject: ...];
[item addObject: ...];
...
[dict setObject: item forKey: theKey];
}
If you don't know all the values for the key from the beginning and need to add them one by one, you can use the following approach:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for( /*some cycling condition here */)
{
id keyToUse = ...;
id valueToAdd = ...;
id foundArray = [dict objectForKey: keyToUse];
if ( nil == foundArray )
{
foundArray = [NSMutableArray array];
[dict setObject: foundArray forKey: keyToUse];
}
[foundArray addObject: valueToAdd];
}
To me it looks you are settings an array (aaa) with string (attri) as a key.
To set an array as a key for another array as an object. You can do this with the following appraoch.
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithCapacity:1];
NSArray *valueArray = [NSArray arrayWithObjects:#"v1", #"v2", nil];
NSArray *keyArray = [NSArray arrayWithObjects:#"k1",#"k2", nil];
[myDictionary setObject:valueArray forKey:keyArray];
NSLog(#"myDictionary: %#", myDictionary);
But you should review your code and provide a more brief explanation that what do you want to achieve and how are you taking an approach for this.
regards,
Arslan

UITableView and CoreData - Displaying Data in Specific Rows and Efficiency?

So, I have a Core data object, let's call it a session (Okay, that's what it actually is called), and it has four attributes (Name, Driver, Track and Car) that I'd like to show in a table view. I've had it working before, but, alas, I'm trying to make my view controllers a little more generic and reusable, so, I'm changing it up a bit. Anywho, here's what the table looks like...
Passed into the view controller is a Session, which is a subclass of NSManagedObject that CoreData whipped up for me. Driver, Car and Track are all object relationships, while name is simply a string. Driver, Car and Track all have a name attribute that I'm displaying in this table. I wanted a quick and dirty way of displaying this text into the table. So, I was doing something like...
NSDictionary *parameterValues = [[NSDictionary alloc] initWithObjectsAndKeys: sessionName, [NSNumber numberWithInt: 0], sessionDriver, [NSNumber numberWithInt: 1], sessionCar, [NSNumber numberWithInt: 2], sessionTrack, [NSNumber numberWithInt: 3], nil];
NSString *parameterString;
if([indexPath row] > 0) {
if([parameterValues objectForKey: [NSNumber numberWithInt: [indexPath row]]] == [NSNull null]) {
parameterString = [[NSString alloc] initWithFormat: #"Select a %#", [parameterNames objectAtIndex: [indexPath row]]];
} else{
parameterString = [[parameterValues objectForKey: [NSNumber numberWithInt: [indexPath row]]] name];
}
} else{
parameterString = [parameterValues objectForKey: [NSNumber numberWithInt: 0]];
if([parameterString isEqualToString: #""]) {
parameterString = #"Enter A Name";
}
}
This worked before I started passing the session as an instance variable, instead of keeping track of specific string, driver, car and track objects. Since [[self session] driver], would return nil when a new session object is passed, a dictionary object cannot be used. This is how I do it now...
//these come in handy, they're the object names (We can use KVC), and we can use them in the table titles
NSArray *parameterNames = [[NSArray alloc] initWithObjects: #"Name", #"Driver", #"Car", #"Track", nil];
//get the object for this row... (Name, Driver, Car, Track), and create a string to hold it's value..
id object = [session valueForKey: [parameterNames objectAtIndex: [indexPath row]]];
NSString *parameterValue;
NSLog(#"%#", [session name]);
//if this isn't the name row...
if(object != nil) {
//if the indexPath is greater than 0, object is not name (NSString)
if([indexPath row] > 0) {
parameterValue = [object name];
} else{
parameterValue = object;
}
} else{
//object doesn't exist yet... placeholder!
parameterValue = [#"Select a " stringByAppendingString: (NSString *)[parameterNames objectAtIndex: [indexPath row]]];
}
What I'm asking is... am I doing this right?
Thanks,
Matt - A Core Data newbie :/
You are over thinking this. If you have a session entity like this:
Session{
name:string
driver<-->Driver
car<-->Car
track<-->Track
}
and Driver, Car and Track all have a name attribute, then all you have to do to populate a fixed table is ask for the attributes value like so:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell=//... get cell however you do it
switch (indexPath.row) {
case 0:
cell.textLabel.text=self.currentSession.name
break;
case 1:
cell.textLabel.text=self.currentSession.driver.name;
break;
//... and so on
default:
break;
}
//... return the cell.
}
Likewise, to get the object to pass to the detail view you just use the same switch statement to get the object associated with the selected row.

How to check if the value in an NSDictionary exists in an array of dictionarys

The title is a bit confusing...I'll explain
I have an NSMutableArray I am populating with NSMutableDictionary objects. What I am trying to do is before the dictionary object is added to the array, I need to check whether any of the dictionaries contain a value equal to an id that is already set.
Example:
Step 1: A button is clicked setting the id of an object for use in establishing a view.
Step 2: Another button is pressed inside said view to save some of its contents into a dictionary, then add said dictionary to an array. But if the established ID already exists as a value to one of the dictionaries keys, do not insert this dictionary.
Here is some code I have that is currently not working:
-(IBAction)addToFavorites:(id)sender{
NSMutableDictionary *fav = [[NSMutableDictionary alloc] init];
[fav setObject:[NSNumber numberWithInt:anObject.anId] forKey:#"id"];
[fav setObject:#"w" forKey:#"cat"];
if ([dataManager.anArray count]==0) { //Nothing exists, so just add it
[dataManager.anArray addObject:fav];
}else {
for (int i=0; i<[dataManager.anArray count]; i++) {
if (![[[dataManager.anArray objectAtIndex:i] objectForKey:#"id"] isEqualToNumber:[NSNumber numberWithInt:anObject.anId]]) {
[dataManager.anArray addObject:fav];
}
}
}
[fav release];
}
One fairly easy way to do this kind of check is to filter the array using an NSPredicate. If there's no match, the result of filtering will be an empty array. So for example:
NSArray *objs = [dataManager anArray];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id == %#", [NSNumber numberWithInt:i]];
NSArray *matchingObjs = [objs filteredArrayUsingPredicate:predicate];
if ([matchingObjs count] == 0)
{
NSLog(#"No match");
}

Problem with fetching dictionary objects in array from plist

What is the datatype you use to fetch items whose type is dictionary in plist i.e. nsmutabledictionary or nsdictionary? Because I'm using following code to retrieve dictionary objects from an array of dictionaries in plist.
NSMutableDictionary *_myDict = [contentArray objectAtIndex:0]; //APP CRASHES HERE
NSLog(#"MYDICT : %#",_myDict);
NSString *myKey = (NSString *)[_myDict valueForKey:#"Contents"] ;
[[cell lblFeed] setText:[NSString stringWithFormat:#"%#",myKey]];
Here, on first line it's showing me objc_msgsend. ContentArray is an nsarray and it's contents are showing 2 objects that are there in plist. In plist they are dictionary objects. Then why this error?
Edit
Basically, the contents of my contentArray in console are as shown below :
CONTENT ARRAY :
(
{
favourites = 0;
id = 0;
story = "This is my first record";
timestamp = 324567;
},
{
favourites = 0;
id = 1;
story = "This is my second record";
timestamp = 321456;
}
)
I want to retrieve these dictionary objects from content array.
NSDictionary. You can't simply say
NSMutableDictionary *_myDict = [contentArray objectAtIndex:0];
and hope, that it's a mutable dictionary now. It's still a normal immutable distionary. So, you should write something like:
NSMutableDictionary *_myDict = [NSMutableDictionary dictionaryWithDictionary:[contentArray objectAtIndex:0]];
That'll create mutable dictionary from one that is in the plist.
You can read about it in the "Property List Programming Guide", http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/PropertyLists/index.html
Update:
Also you have a strange plist contents. Available xml-plist types are mentioned here:
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/PropertyLists/AboutPropertyLists/AboutPropertyLists.html#//apple_ref/doc/uid/10000048i-CH3-SW1
And overall xml-plist structure is described here:
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/PropertyLists/UnderstandXMLPlist/UnderstandXMLPlist.html#//apple_ref/doc/uid/10000048i-CH6-SW1
Working piece of code
void test() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *arrayIWillWrite = [NSMutableArray array];
NSMutableDictionary *dictionary;
dictionary = [NSMutableDictionary dictionary];
[dictionary setObject:[NSNumber numberWithInt:0] forKey:#"favourites"];
[dictionary setObject:[NSNumber numberWithInt:0] forKey:#"id"];
[dictionary setObject:#"This is my first record" forKey:#"story"];
[dictionary setObject:[NSNumber numberWithInt:324567] forKey:#"timestamp"];
[arrayIWillWrite addObject:dictionary];
dictionary = [NSMutableDictionary dictionary];
[dictionary setObject:[NSNumber numberWithInt:0] forKey:#"favourites"];
[dictionary setObject:[NSNumber numberWithInt:1] forKey:#"id"];
[dictionary setObject:#"This is my second record" forKey:#"story"];
[dictionary setObject:[NSNumber numberWithInt:321456] forKey:#"timestamp"];
[arrayIWillWrite addObject:dictionary];
[arrayIWillWrite writeToFile:#"/Users/alex/test.plist" atomically:NO];
NSArray *arrayThatWasRead = [NSArray arrayWithContentsOfFile:#"/Users/alex/test.plist"];
NSLog(#"%#", arrayThatWasRead);
NSDictionary *dictionaryFromArrayThatWasRead = [arrayThatWasRead objectAtIndex:0];
NSLog(#"%#", dictionaryFromArrayThatWasRead);
[pool release];
}