Lewis
Lewis

Reputation: 159

Compare array elements with eachother, on duplicates add a certain property together?

I'm trying to loop through my array and find duplicate objects based on the name properties of the objects in the array. Once a duplicate is found I need to combine these objects, the name and unit values stay the same, I just want to add the quantity values together. At this point I want to remove the two duplicates and add the new object to the array instead.

If its two difficult to remove two objects and add another (might mess with the index?) then the new objects could be added to a filtered array, as long as when a duplicate isnt found that is also added to this array. So the new array will contain all of my previous values, with duplicate values combine on quantity.

I have this so far:

NSMutableSet* existingNames = [NSMutableSet set];
NSMutableArray* filteredArray = [NSMutableArray array];

for (id object in ingredientsArray)
{
    if (![existingNames containsObject:[object name]])
    {
        [existingNames addObject:[object name]];
        NSLog(@"%@", @"DUPLICATE FOUND");

        //create new object to store the new info in.
        ingredient *info = [[ingredient alloc] initWithname:[object name] quantity:[/* How do I add the quanitity values of the two objects that are duplicates here? */] unit:[object unit]];

        //add this to filtered array.
        [filteredArray addObject:object];

        //remove object from array.
        [ingredientsArray removeObject:object];
    }
}

thanks

Upvotes: 0

Views: 181

Answers (1)

Mundi
Mundi

Reputation: 80273

You cannot modify an array that you are enumerating. The compiler should complain about this, if not, it should crash at runtime.

I think the logic in your code is bit messed up. The if clause checks if the string is not contained in your duplicates array - so "DUPLICATE FOUND" is certainly not true.

It is bad practice to just iterate through id in this case. It would be better if you could type your objects more strongly. It is also advised to adhere to the conventions such as Capitalized class names.

One trick to reduce the iterations is to just iterate through the unique names. There is a trick with NSSet to accomplish this:

NSArray *names = [ingredientsList valueForKeyPath:@"name"];
NSSet *uniqueNames = [NSSet setWithArray:names];
NSArray *resultArray = [NSMutableArray array];
NSPredicate *nameFilter;

for (NSString *ingredientName in uniqueNames) {
   predicate = [NSPredicate predicateWithFormat:@"name = %@", ingredientName];
   NSArray *entries = [ingredientsList filteredArrayUsingPredicate:predicate];
   Ingredient *ingredient = entries[0];
   if (entries.count > 1) {
      NSLog(@"Found %d instances of %@.", entries.count, ingredientName);
      NSNumber *sum = [entries valueForKeyPath:@"@sum.quantity"];
      ingredient.quantity = sum;
   }
   [resultsArray addObject:ingredient];
}

This assumes that the class Ingredient has at least two properties, name (NSString) and quantity (NSNumber). This also works with plain NSDictionaries.

Upvotes: 2

Related Questions