Jenny
Jenny

Reputation: 351

remove object from NSMutableArray by key

NSMutableArray *array = [NSMutableArray arrayWithObjects:@{@"name":@"Jenny",@"age":@23},@{@"name":@"Daisy",@"age":@27},nil];

Is it possible to remove object by key in the array's dictionary object?

For example. remove object by age = 27

Upvotes: 4

Views: 3238

Answers (4)

Mike
Mike

Reputation: 9835

I'm not sure if there's a more direct method or not, but one way to do it would be to simply iterate through the array and test the values. You can't mutate an array while enumerating, meaning you cant remove an object while iterating through it, so one method is to obtain the index of the object that matches your criteria, and if you find one, break, and remove the item at that index. Something like the following:

NSInteger indexToDelete = -1;

for (NSInteger i = 0; i < array.count; i++) {
   NSDictionary *dict = array[i];

   if ([dict[@"age"] integerValue] == 27) {
      indexToDelete = i;
      break;      
   }
}

if (indexToDelete > 0) {
   [array removeObjectAtIndex:indexToDelete];
}

Intrigued by the other answers using filteredArrayUsingPredicate, I was curious about performance and decided to do a side-by-side performance test using Xcode's measureBlock feature. Iterating through an array of 1,000 dictionaries, removing one item that matches an integer value from each array, and comparing when the item is very close to the beginning of the array, the middle of the array, and the end of the array, both versions tended to complete within a few thousandths of a second of the other, with the predicate filter being very slightly faster in every case. (We're talking around .269 seconds vs .261 seconds)

With that in mind, I would think that neither is better than the other in any major sense, it just comes down to preference. I do think the filteredArrayUsingPredicate method is cleaner though. Just some additional food for thought for anyone curious, and gave me a reason to try out the measureBlock feature on my own. :)

Upvotes: 3

matt
matt

Reputation: 535129

To filter objects out of an NSArray, call filteredArrayUsingPredicate:

NSArray *array = @[@{@"name":@"Jenny",@"age":@23},@{@"name":@"Daisy",@"age":@27}];
NSArray *array2 =
  [array filteredArrayUsingPredicate:
   [NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *d) {
      return ![[obj valueForKey:@"age"] isEqual:@27];
  }]];

Now array2 is the desired array - it is the first array without the one whose age is 27.

By the way, I know this is not what you asked, but that sort of thing is a great reason to switch to Swift. It is soooooo much simpler; this sort of problem is like a living neon technicolor advertisement for Swift:

let array = [["name":"Jenny", "age":23],["name":"Daisy", "age":27]]
let array2 = array.filter {$0["age"] != 27}

Upvotes: 8

user3386109
user3386109

Reputation: 34829

You can use NSPredicate to create a new array that's missing the unwanted entry. NSPredicate is similar to a database query where the input NSArray represents the database, and the output array is the response to the query.

NSArray *array = @[  @{@"name":@"Jenny",@"age":@23},
                     @{@"name":@"Daisy",@"age":@27}  ];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age != 27"];
NSArray *filtered = [array filteredArrayUsingPredicate:predicate];

NSLog( @"%@", array );
NSLog( @"%@", filtered );

Upvotes: 4

NRaf
NRaf

Reputation: 7549

In this case, you'll have to loop through each item and do a manual test against each object, which may be fine depending on the size of data you're dealing with and the complexity of your use cases.

Alternatively, consider storing the data in a sqlite database and querying against it if it's practical for you.

Upvotes: 1

Related Questions