Any idea how to do this in Swift 3?
let number: NSArray = [123, 456, 678]
let check = "1"
let predicate = NSPredicate(format: "number.stringValue CONTAINS %#", check)
number.filtered(using: predicate)
The problem is .stringValue. Any idea how this can be done without using a block predicate and not using the standard filter function, but with a predicate as above?
The name of the array variable (here: "number") is not part of the key path of the array elements, so it is just:
let number: NSArray = [123, 456, 678]
let check = "6"
let predicate = NSPredicate(format: "stringValue CONTAINS %#", check)
print(number.filtered(using: predicate)) // [456, 678]
Or with "SELF", if you want to be more explicit:
let predicate = NSPredicate(format: "SELF.stringValue CONTAINS %#", check)
The "SELF" keyword is explained in Predicate Format String Syntax in the "Predicate Programming Guide":
SELF
Represents the object being evaluated.
Related
I have a dictionary with ~100k entries and provide a search function where the user can search for a string in english/chinese and all entries that contain this string will be displayed. An entry has the structure:
class DictionaryEntry: Object, Identifiable {
#objc dynamic var id: String = NSUUID().uuidString
#objc dynamic var character: String = ""
#objc dynamic var pinyin: String = ""
#objc dynamic var definition: String = ""
}
Let's say we have the following two entries:
entry1 = "宝山 / Bǎoshān / Bǎoshān district of Shanghai"
entry2 = "上海 / Shànghǎi / Shanghai"
and the search string is "shanghai". I filter the entries by this way:
let realm = try! Realm()
realm.objects(DictionaryEntry.self)
.filter("pinyin CONTAINS[cd] %# OR definition CONTAINS[cd] %# OR character CONTAINS[cd] %#", searchString, searchString, searchString)
//.sorted(by: ???)
Since both entries contain the search string both entries will appear, but they are not sorted by any logic yet. I would like to sort the results by the highest "coverage/matching". So first should "Shanghai" appear, then "Shanghai university", ..., and at the end entries like "Old canal between Suzhou and Shanghai". Is there any built-in realm solution?
Realm's Results have built-in methods for sorting, see Sorting in the docs.
If you want to sort based on a specific property, you can use sorted(byKeyPath:) which takes a single String representing the property name that you want to sort by:
let realm = try! Realm()
realm.objects(DictionaryEntry.self)
.filter("pinyin CONTAINS[cd] %# OR definition CONTAINS[cd] %# OR character CONTAINS[cd] %#", searchString, searchString, searchString)
.sorted(byKeyPath: "pinyin")
Or if you want to sort based on all 3 properties that you are filtering by, you can use sorted(by:), which takes a Sequence of SortDescriptor objects, which can be created based on key paths as well:
let realm = try! Realm()
realm.objects(DictionaryEntry.self)
.filter("pinyin CONTAINS[cd] %# OR definition CONTAINS[cd] %# OR character CONTAINS[cd] %#", searchString, searchString, searchString)
.sorted(by: [SortDescriptor(keyPath: "pinyin"), SortDescriptor(keyPath: "definition"), SortDescriptor(keyPath: "character")])
I have a coreData fetchRequest that filters results based on a searchString entered by the user.
I want the results to begin with the same prefix as the searchString rather than just beginning alphabetically or in any other order.
For example if my array is:
["apple", "banana", "cherry", "durian", "raspberry"]
and my searchString entered in the search bar is "r", I would like "raspberry" to be the first result returned followed by "cherry" and "durian"
For the above my predicate is:
request.predicate = NSPredicate(format: "item.itemName CONTAINS[cd] %#", self.searchString)
At the moment my sortDescriptor is:
let prefixSort = ???
let nameSort = NSSortDescriptor(key: "item.itemName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
request.sortDescriptors = [prefixSort, nameSort]
Not sure how to enter the prefixSort so that the results will be sorted for the prefix being the searchString taking priority
In Swift 4 I have a CoreData "Sentence" model that has a String attribute "englishsentence". I also have an array of "words" and would like to fetch all sentences for which the "englishsentence" attribute contains one or more of the words in the array.
var words = ["today", "yesterday", "tomorrow"]
This array is just an example. It is supposed to change at runtime and can have any length.
and in the fetch request I am trying to do something like this:
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Sentence")
let predicate = NSPredicate(format: "ANY englishsentence CONTAINS ANY word IN %#", words)
fetchRequest.predicate = predicate
I am able to create a predicate for all sentences that contain one particular word. However, I cannot get it to work with an array of words unless of course I iterate through the words-array and make a new fetch request for every single word. But this seems awfully inefficient.
One option would be to create a “compound predicate:”
let words = ["today", "yesterday", "tomorrow"]
let predicates = words.map {
NSPredicate(format: "englishsentence CONTAINS %#", $0)
}
let predicate = NSCompoundPredicate(orPredicateWithSubpredicates: predicates)
Another option is to match against a regular expression:
let regex = ".*(" + words.map {
NSRegularExpression.escapedPattern(for: $0)
}.joined(separator: "|") + ").*"
let predicate = NSPredicate(format: "englishsentence MATCHES %#", regex)
To match only “whole words” you can add the word boundary pattern \b:
let regex = ".*\\b(" + words.map {
NSRegularExpression.escapedPattern(for: $0)
}.joined(separator: "|") + ")\\b.*"
How do you combine two conditions in NSPredicate? I am using the following statement and I would like to add another condition that compares the the password with the contents of a textfield using AND:
request.predicate = NSPredicate(format: "username = %#", txtUserName.text!)
As already said, you can use logical operators like "AND", "OR"
in predicates. Details can be found in
Predicate Format String Syntax in the "Predicate Programming Guide".
As an alternative, use "compound predicates":
let p1 = NSPredicate(format: "username = %#", "user")
let p2 = NSPredicate(format: "password = %#", "password")
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [p1, p2])
This is useful for more complex expressions, or if you want to build
a predicate dynamically at runtime.
Try this
request.predicate = NSPredicate(format: "username = %# AND password = %#", txtUserName.text!, txtPassword.text!)
AND is exactly what you need
request.predicate = NSPredicate(format: "username = %# AND password = %#", txtUserName.text!, txtPassWord.text!)
I need to create a CKQuery where the predicate contains a reference of a record, and not a field of the record.
Like this
let query = CKQuery(recordType: "OUP", predicate: NSPredicate(format: "o = %#", "FF4FB4A9-271A-4AF4-B02C-722ABF25BF44")
How do I set o is a CKReference, not field!
I get this error:
Field value type mismatch in query predicate for field 'o'
You can use a CKRecord or CKRecordID, with or without a CKReference, to match relationships.
CKRecord:
let predicate = NSPredicate(format: "artist == %#", artist)
CKRecordID:
let predicate = NSPredicate(format: "artist == %#", artistID)
CKReference with CKRecord:
let recordToMatch = CKReference(record: artist, action: CKReferenceAction.None)
let predicate = NSPredicate(format: "artist == %#", recordToMatch)
CKReference with CKRecordID:
let recordToMatch = CKReference(recordID: artistID, action: CKReferenceAction.None)
let predicate = NSPredicate(format: "artist == %#", recordToMatch)
I found in CKQuery class reference the answer, or at least an example how to use CKReference in CKQuery:
CKReference* recordToMatch = [[CKReference alloc] initWithRecordID:employeeID action:CKReferenceActionNone];
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"employee == %#", recordToMatch];
To match records that link to a different record whose ID you know, create a predicate that matches a field containing a reference object as shown in Listing 1. In the example, the employee field of the record contains a CKReference object that points to another record. When the query executes, a match occurs when the ID in the locally created CKReference object is the same ID found in the specified field of the record.