NSArray
NSPredicate
NOT IN operator
Objective-C
iOS Development

NSArray with NSPredicate using NOT IN

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

NSPredicate offers concise, readable filtering for Objective-C collections, and NOT IN is a practical way to exclude known values. This pattern appears in permission filtering, de-duplication workflows, and local cache cleanup. Correct results depend on matching predicate syntax to collection shape and controlling type and case behavior.

Basic NOT IN for Value Arrays

For arrays of plain strings or numbers, use SELF as the subject and pass the exclusion array as an argument.

objective-c
1NSArray *allTags = @[@"ios", @"backend", @"kafka", @"ml"];
2NSArray *blocked = @[@"backend", @"ml"];
3
4NSPredicate *p = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", blocked];
5NSArray *visible = [allTags filteredArrayUsingPredicate:p];
6
7NSLog(@"%@", visible); // ios, kafka

The parentheses are important for clarity when you later add more conditions.

Filtering Object Collections by Field

When the collection contains dictionaries or model objects, target a key path instead of SELF.

objective-c
1NSArray *users = @[
2    @{@"name": @"Ari", @"role": @"admin"},
3    @{@"name": @"Bea", @"role": @"guest"},
4    @{@"name": @"Cam", @"role": @"editor"}
5];
6
7NSArray *blockedRoles = @[@"guest"];
8NSPredicate *p = [NSPredicate predicateWithFormat:@"NOT (role IN %@)", blockedRoles];
9NSArray *allowed = [users filteredArrayUsingPredicate:p];
10
11NSLog(@"%@", allowed);

The same pattern works for numeric ids, states, and categories.

Combining Exclusion With Additional Rules

You can compose NOT IN with logical conditions to keep query logic in one place.

objective-c
1NSArray *orders = @[
2    @{@"id": @1, @"state": @"paid", @"amount": @120},
3    @{@"id": @2, @"state": @"cancelled", @"amount": @200},
4    @{@"id": @3, @"state": @"paid", @"amount": @50}
5];
6
7NSArray *badStates = @[@"cancelled", @"fraud"];
8NSPredicate *p = [NSPredicate predicateWithFormat:@"NOT (state IN %@) AND amount >= 100", badStates];
9NSArray *result = [orders filteredArrayUsingPredicate:p];
10
11NSLog(@"%@", result); // id 1

This is usually cleaner than nested loops with manual condition flags.

Case and Type Normalization

IN checks exact equality. If values differ by case or type, the predicate may exclude the wrong set.

Two useful rules:

  • normalize case before filtering when data source is inconsistent
  • keep exclusion list type aligned with target field type

Case normalization example:

objective-c
1NSArray *names = @[@"Admin", @"Guest", @"Editor"];
2NSArray *excluded = @[@"guest"];
3
4NSArray *normNames = [names valueForKey:@"lowercaseString"];
5NSArray *normExcluded = [excluded valueForKey:@"lowercaseString"];
6
7NSPredicate *p = [NSPredicate predicateWithFormat:@"NOT (SELF IN %@)", normExcluded];
8NSArray *filtered = [normNames filteredArrayUsingPredicate:p];
9
10NSLog(@"%@", filtered);

If original casing matters, keep a parallel mapping to original objects.

Performance Strategy for Larger Lists

For moderate arrays, filteredArrayUsingPredicate is sufficient. For frequent large-batch filtering:

  • precompute a normalized exclusion set once per refresh cycle
  • reuse predicate instances when the same rule runs repeatedly
  • avoid dynamic predicate construction inside tight loops

Micro-optimizations should follow profiling. Premature tuning can reduce readability without measurable gain. When filtering is done on background queues, keep mutable source arrays immutable during evaluation so results stay deterministic and easy to debug.

Safe Dynamic Predicate Construction

If parts of the predicate come from user controls, avoid directly concatenating raw strings into the format. Use argument substitution and vetted field names.

objective-c
1NSString *field = @"role"; // validated from whitelist
2NSArray *blocked = @[@"guest"];
3NSString *format = [NSString stringWithFormat:@"NOT (%@ IN %@)", field, @"%@"];
4NSPredicate *p = [NSPredicate predicateWithFormat:format, blocked];

Keep dynamic construction constrained to trusted field options. For debugging, log the final predicate format and sample inputs in non-production builds. This helps detect malformed rules early during QA without exposing user data in production logs.

Common Pitfalls

  • Using SELF for dictionary arrays where a field key path is required.
  • Forgetting parentheses in NOT (x IN y) when combining with AND or OR.
  • Assuming comparisons are case-insensitive by default.
  • Mismatching value types between source data and exclusion list.
  • Rebuilding predicates repeatedly in hot paths without profiling evidence.

Summary

  • NOT IN is a concise way to exclude values from NSArray filters.
  • Use SELF for primitive values and key paths for object fields.
  • Normalize case and types to prevent subtle mismatches.
  • Compose exclusion logic with other predicates for readable filtering.
  • Profile before optimizing, and keep predicate construction safe and explicit.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.