How to filter NSArray in Swift?
Here's what I ended up doing:
let resultPredicate = NSPredicate(format: "name contains[c] %@", searchText)
self.filteredUserData = self.userData.filteredArrayUsingPredicate(resultPredicate)
Objective-C version:
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", searchText];
self.filteredUserData = [self.userData filteredArrayUsingPredicate:resultPredicate];
How to filter an array using NSPredicate in swift 3
The native Swift equivalent to the ObjC code is
let filteredArray = arrayDirectory.filter { ($0["displayName2"] as! String).range(of: searchText!, options: [.diacriticInsensitive, .caseInsensitive]) != nil }
assuming arrayDirectory
is a native Swift Array
. It considers also the case insensitive
and diacritic insensitive
parameters.
How to filter NSArray using predicate on an object property
Try following lines, and make sure properyName
is case sensitive. and you have placed ,
in predicate format, thats why its not working. just replace your code with following.
Objective C
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:@"SELF.name contains[cd] %@",self.searchText.text];
self.filteredArray = [self.hotelArray filteredArrayUsingPredicate:bPredicate];
NSLog(@"HERE %@",self.filteredArray);
Swift
var bPredicate: NSPredicate = NSPredicate(format: "SELF.name contains[cd] %@", self.searchText.text)
self.filteredArray = self.hotelArray.filteredArrayUsingPredicate(bPredicate)
NSLog("HERE %@", self.filteredArray)
Using swift filter
var searchText = "Galaxy"
let filteredArray = hotelArray.filter { $0["name"] == searchText }
print("** Result ** \n\(filteredArray)")
Swift 3.0
let arrEmp = [["name": "James", "age" : 27, "city" : "New york"],
["name": "Johnson", "age" : 24, "city" : "London"],
["name": "Alex", "age" : 28, "city" : "Newark"],
["name": "Mark", "age" : 25, "city" : "Paris"],
["name": "Steve", "age" : 25, "city" : "Silicon Valley"],
["name": "Lary", "age" : 28, "city" : "New york"]]
// *** Filter by Name exact match ***
var filterByName = arrEmp.filter { $0["name"] == "Mark" }
print("filterByName \(filterByName)")
// *** Filter by Age ***
var filterByAge = arrEmp.filter { $0["age"] as! Int > 25 }
print("filterByAge \(filterByAge)")
Swift 4.0
var filterByName = arrEmp.filter
do {
$0["name"] == "Mark"
}
print("filterByName filterByName)")
var filterByAge = arrEmp.filter
do {
$0["age"] as! Int > 25
}
print("filterByAge filterByAge)")
I filtered an NSMutableArray of Dictionaries and then I want to filter for a Key again
- Don't use
NSArray
orNSMutableArray
in Swift. Use Swift native arrays (and dictionaries). - Once you do that, there is no need for
NSPredicate
. Use thefilter
method. - Don't use a dictionary to hold your data. Create a
struct
with the needed fields.
First, without creating a struct
, here's a simply solution using native arrays:
var dataArray = [[String:Any]]()
var sum = 0.00
func addNewIncomeRecord(_ id: String, date: String, description: String, amount: Double, currency: String, category: String, notes: String) {
let dict: [String:Any] = ["id" : id, "date" : date, "description" : description, "amount" : amount, "currency" : currency, "category" : category, "notes" : notes]
dataArray.append(dict)
}
addNewIncomeRecord("1", date: "11-25", description: "Money", amount: 20.00, currency: "EUR", category: "Home", notes: "More Money")
addNewIncomeRecord("2", date: "11-25", description: "Rent", amount: 50.00, currency: "EUR", category: "Home", notes: "Rent Money")
addNewIncomeRecord("3", date: "11-25", description: "Hair", amount: 10.00, currency: "EUR", category: "Medical" ,notes: "HairCut")
let filteredArray = dataArray.filter { $0["category"] as? String == "Home" }
let amounts = filteredArray.flatMap { $0["amount"] as? Double }
print(amounts)
Here's the solution making use of a struct
.
struct Income {
let id: String
let date: String
let description: String
let amount: Double
let currency: String
let category: String
let notes: String
}
var dataArray = [Income]()
var sum = 0.00
func addNewIncomeRecord(_ id: String, date: String, description: String, amount: Double, currency: String, category: String, notes: String) {
let income = Income(id: id, date: date, description: description, amount: amount, currency: currency, category: category, notes: notes)
dataArray.append(income)
}
addNewIncomeRecord("1", date: "11-25", description: "Money", amount: 20.00, currency: "EUR", category: "Home", notes: "More Money")
addNewIncomeRecord("2", date: "11-25", description: "Rent", amount: 50.00, currency: "EUR", category: "Home", notes: "Rent Money")
addNewIncomeRecord("3", date: "11-25", description: "Hair", amount: 10.00, currency: "EUR", category: "Medical" ,notes: "HairCut")
let filteredArray = dataArray.filter { $0.category == "Home" }
let amounts = filteredArray.map { $0.amount }
print(amounts)
Using a struct
has many advantages. It's type safe for each field. You can make it Codable
which makes it a lot easier to save and read from a file.
Filter NSArray based on another array using predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"not (self.username IN %@)", [some_usernames valueForKey:@"username"]];
NSArray *remaining_usernames = [all_usernames filteredArrayUsingPredicate:predicate];
complete example
@interface Alpha : NSObject
@property (nonatomic, copy) NSString *username;
-(instancetype) initWithUsername:(NSString *)username;
@end
@implementation Alpha
-(instancetype) initWithUsername:(NSString *)username
{
self = [super init];
if (self) {
self.username = username;
}
return self;
}
-(NSString *)description{
return [NSString stringWithFormat:@"%@: %@", NSStringFromClass([self class]), self.username];
}
@end
NSArray *all_usernames = @[[[Alpha alloc] initWithUsername:@"a"], [[Alpha alloc] initWithUsername:@"b"], [[Alpha alloc] initWithUsername:@"z"], [[Alpha alloc] initWithUsername:@"f"], [[Alpha alloc] initWithUsername:@"e"]];
NSArray *some_usernames = @[[[Alpha alloc] initWithUsername:@"b"], [[Alpha alloc] initWithUsername:@"f"]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"not (self.username IN %@)", [some_usernames valueForKey:@"username"]];
NSArray *remaining_usernames = [all_usernames filteredArrayUsingPredicate:predicate];
NSLog(@"%@", remaining_usernames);
prints
(
"Alpha: a",
"Alpha: z",
"Alpha: e"
)
Search in NSMutableArray
Instead of extracting and filtering the "name"
values you can filter the array directly, using the corresponding key path instead of “SELF” in the predicate:
let array = NSArray(array: [
["id": 1, "name": "x1"], ["id": 2, "name": "x2"], ["id": 3, "name": "y3"]])
let predicate = NSPredicate(format: "name BEGINSWITH [c] %@", "x")
let filtered = array.filtered(using: predicate)
print(filtered)
Result:
[{
id = 1;
name = x1;
}, {
id = 2;
name = x2;
}]
Another option is to cast the NS(Mutable)Array
to a Swift array of dictionaries, and use the filter()
function:
if let a = array as? [[String: Any]] {
let filtered = a.filter {
($0["name"] as? String)?
.range(of: "x", options: [.caseInsensitive, .anchored]) != nil
}
print(filtered)
// [["id": 1, "name": x1], ["name": x2, "id": 2]]
}
filtering NSArray into a new NSArray in Objective-C
NSArray
and NSMutableArray
provide methods to filter array contents. NSArray
provides filteredArrayUsingPredicate: which returns a new array containing objects in the receiver that match the specified predicate. NSMutableArray
adds filterUsingPredicate: which evaluates the receiver’s content against the specified predicate and leaves only objects that match. These methods are illustrated in the following example.
NSMutableArray *array =
[NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil];
NSPredicate *bPredicate =
[NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
NSArray *beginWithB =
[array filteredArrayUsingPredicate:bPredicate];
// beginWithB contains { @"Bill", @"Ben" }.
NSPredicate *sPredicate =
[NSPredicate predicateWithFormat:@"SELF contains[c] 's'"];
[array filteredArrayUsingPredicate:sPredicate];
// array now contains { @"Chris", @"Melissa" }
Related Topics
How to Call a Func Within a Closure
How to Get Exactly the Same Point on Different Screen Sizes
Exc Bad Access After Coding Signing
Why Can't I Use 'Type' as the Name of an Enum Embedded in a Struct
How to Make a Variable from a String
Where to Implement Nsvaluetransformer for Core Data in Swift
Finding All Types That Conform to a Protocol
How to Execute Different Implementation of a Method of a Generic Struct Based on the Generic Type
Receiving Data from Nsinputstream in Swift
What Does the Underscore in a Function Declaration Do
Swift: Implementing Protocol Initializer in a Class
How to Loop All Firebase Children at Once in the Same Loop
Bulk Fix Hundreds of "#Selector Not Exposed to Objective-C" Errors in Xcode 9 or 9.1
Compare Value from Two Struct in Swift
Core Data Update in Swift While Selecting Any Row in List Table View Not Working