I have a question, I do have an array which holds dictionaries, these dictionaries then go into a tableView. Now I need a search Function to filter the Table.
For example: I have that kind of Array/Dictionary
var filteredItems = [[String: String]]()
var unfilteredItems = [[String: String]]()
and then I wanted to filter that with a function like this
func filterContentForSearch (searchText:String, scope: Int) {
self.filteredItems = self.unfilteredItems.filter({ (description: String) -> Bool in
var searchMatch = description.rangeOfString(searchText)
return searchMatch != nil
})
}
My feeling says there is something wrong and it don't work, so far I couldn't figure out what could be the issue or an approach which could work... any ideas?
The error message I get from Xcode is: "[String, String] is not a subtype of String
Running on Xcode 6.1.1
Thanks for your help...
You have dictionaries in unfilteredItems array. But you treat them as String inside filter closure. Correct type should be
(description: [String: String]) -> Bool
Try this:
var filteredItems : NSArray = [];
var unfilteredItems : NSArray = []; // this array should contain your string data
func filterContentForSearch (searchText:String, scope: Int) {
if let predicate = NSPredicate(format: "SELF CONTAINS %#", searchText) {
self.filteredItems = self.unfilteredItems.filteredArrayUsingPredicate(predicate)
}
else
self.filteredItems = nil;
}
Here is how I did it:
func filterContentForSearch (searchText:String, scope: Int) {
self.unfiltredItems = filtredItems.filter({
$0["description"] == searchText
})
}
Very simple but it works...
Related
I have an arraycontaining several dictionaries.
{
DisplayName?:"Name of the employee"
Age:28
Department:"Dept 2"
}
I just converted my objective-c code into swift and trying to filter like this.
let exists = NSPredicate(format: "DisplayName2 CONTAINS[cd] \(searchText!)")
let aList: Array<Any> = arrayDirectory.filter { exists.evaluate(with: $0) }
if(aList.count>0)
{
arrayDirectory=aList
facesCarousel.reloadData()
}
But I am always getting the aList count as 0. It seems like not filtering my array. How can I write proper NSPredicatein swift 3 and filter my array using it.
To make this filter in Swift doesn't require NSPredicate at all.
let array = arrayDirectory.filter {
guard let name = $0["DisplayName"] as? String else {
return false
}
return name.contains(searchText)
}
That should be all you need.
EDIT
Updated to match your dictionary. I think this is what you're doing.
Ideally, you shouldn't be using a standard Dictionary as a working object. Convert your array of dictionaries to an array of Structs. That way you don't need to stringly type your code or unwrap properties that aren't really optional.
Workaround for working with an [Any] array...
Because you have defined your array as [Any] (don't do this) you will need to convert the object to a dictionary first.
let array = arrayDirectory.filter {
guard let dictionary = $0 as? [String: Any],
let name = dictionary["DisplayName"] as? String else {
return false
}
return name.contains(searchText)
}
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.
you can try
self.arrayDirectory.filter({(($0["Age"] as! String).localizedCaseInsensitiveContains(searchText))!})
Use this code my code will help you
let predicate = NSPredicate(format: "DisplayName2 contains[c] %#", textField.text!)
let arr : NSArray = arrayDirectory.filtered(using: predicate) as NSArray
if arr.count > 0
{
arrayDirectory=arr
facesCarousel.reloadData()
}
Use this code its worked fine in my side I hope this code will be help you
I have an array that array containing several dictionaries. Structure will be like this
[
{
DisplayName:"Name of the employee1"
Age:28
Department:"Dept 2"
}
]
In above array i am filtering with displayName key using apple search controller with help of predicate method
func updateSearchResults(for searchController: UISearchController) {
if (searchController.searchBar.text?.characters.count)! > 0 {
guard let searchText = searchController.searchBar.text, searchText != "" else {
return
}
let searchPredicate = NSPredicate(format: "DisplayName CONTAINS[C] %#", searchText)
usersDataFromResponse = (filteredArray as NSArray).filtered(using: searchPredicate)
print ("array = \(usersDataFromResponse)")
self.tableview.reloadData()
}
}
I have a class such as this
class FoundItem : NSObject {
var id : String!
var itemName : String!
var itemId : Int!
var foundBy : String!
var timeFound : String!
init(id: String,
itemName: String,
itemId: Int,
foundBy: String,
timeFound: String)
{
self.id = id
self.itemName = itemName
self.itemId = itemId
self.foundBy = foundBy
self.timeFound = timeFound
}
and I reference it on my
class MapViewVC: UIViewController, MKMapViewDelegate {
var found = [FoundItem]()
var filterItemName : String()
}
My FoundItem are generated by into an array of dictionaries from my class of FoundItem from a firebase query. I then get a string of that itemName that is generated from an another view controller that is a collection view on the didSelection function. I want to take that string and then filter or search the arrays with the string itemName that is equal from the itemName string from my previous viewController. Then removed the array of dictionaries that are not equal to the itemName. Not just the objects, but the entire array that contains non-equal key, value pair. I have looked for days, and I am stuck on filtering an array of dictionaries created from a class. I have looked and tried NSPredicates, for-in loops, but all that ends up happening is creating a new array or bool that finds my values or keys are equal. Here is the current function I have written.
func filterArrayBySearch() {
if self.filterItemName != nil {
dump(found)
let namePredicate = NSPredicate(format: "itemName like %#", "\(filterItemName)")
let nameFilter = found.filter { namePredicate.evaluate(with: $0) }
var crossRefNames = [String: [FoundItem]]()
for nameItemArr in found {
let listName = nameItem.itemName
let key = listName
if crossRefNames.index(forKey: key!) != nil {
crossRefNames[key!]?.append(nameItemArr)
if !("\(key)" == "\(filterItemName!)") {
print("------------- Success have found [[[[[[ \(key!) ]]]]]] and \(filterItemName!) to be equal!!")
// crossRefNames[key!]?.append(nameItemArr)
} else {
print("!! Could not find if \(key!) and \(filterItemName!) are equal !!")
}
} else {
crossRefNames[key!] = [nameItemArr]
}
}
} else {
print("No Data from Search/FilterVC Controller")
}
}
Can anyone help? It seems like it would be the simple task to find the value and then filter out the dictionaries that are not equal to the itemName string, but I keep hitting a wall. And running into for-in loops myself :P trying different things to achieve the same task.
I hope I understood what you were asking. You mention an "array of dictionaries" but you don't actually have an array of dictionaries anywhere in the code you've posted.
As far as I can tell, you are asking how to find all the entries in the found array for which itemName equals the filterItemName property.
If so, all you should need to do is:
let foundItems = found.filter { $0.itemName == filterItemName }
That's it.
Some other ideas:
If you want to search for items where filterItemName is contained in the itemName, you could do something like this:
let foundItems = found.filter { $0.itemName.contains(filterItemName) }
You could also make use of the lowercased() function if you want to do case-insensitive search.
You could also return properties of your found elements into an array:
let foundIds = found.filter { $0.itemName == filterItemName }.map { $0.itemId }
Sort array of dictionary using the following way
var dict:[[String:AnyObject]] = sortedArray.filter{($0["parentId"] as! String) == "compareId"}
The filter function loops over every item in a collection, and returns a collection containing only items that satisfy an include condition.
We can get single object from this array of dictionary , you can use the following code
var dict = sortedArray.filter{($0["parentId"] as! String) == "compareId"}.first
OR
let dict = sortedArray.filter{ ($0["parentId"] as! String) == "compareId" }.first
Local search filter using predicate in array of dictionary objects
with key name this code use for both swift3 and swift4,4.1 also.
func updateSearchResults(for searchController:
UISearchController) {
if (searchController.searchBar.text?.characters.count)! > 0 {
guard let searchText = searchController.searchBar.text,
searchText != "" else {
return
}
usersDataFromResponse.removeAll()
let searchPredicate = NSPredicate(format: "userName
CONTAINS[C] %#", searchText)
usersDataFromResponse = (filteredArray as
NSArray).filtered(using: searchPredicate)
print ("array = \(usersDataFromResponse)")
self.listTableView.reloadData()
}
}
Here I use CoreData And I have Array of Dictionary .
Here I am filter the key paymentToInvoice that value is invoice array then key invoiceToPeople that key contain People Dictionary then I search FirstName, lastName, Organization multiple key contain searchText.
I hope it's helps Please try this Thank You
var searchDict = dict.filter { (arg0) -> Bool in
let (key, value) = arg0
for paymentInfo in (value as! [PaymentInfo]){
let organization = (Array((value as! [PaymentInfo])[0].paymentToInvoice!)[0] as! InvoiceInfo).invoiceToPeople?.organization
let firstName = (Array((value as! [PaymentInfo])[0].paymentToInvoice!)[0] as! InvoiceInfo).invoiceToPeople?.firstName
let lastName = (Array((value as! [PaymentInfo])[0].paymentToInvoice!)[0] as! InvoiceInfo).invoiceToPeople?.lastName
return organization?.localizedStandardRange(of: searchText) != nil || firstName?.localizedStandardRange(of: searchText) != nil || lastName?.localizedStandardRange(of: searchText) != nil
}
return true
}
I've the following array of objects which I'm trying to filter and return for a searchDosplayController.
var family = [Family]()// fetchedFamily
var filteredFamily: [Family]! // filter fetched events
And that is how, I'm filtering it:
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchText = searchController.searchBar.text
self.filteredProvince = provinces
if !searchText.isEmpty {
let searchPredicate = NSPredicate(format: "name CONTAINS[c] %#", searchText)
let array = (filteredProvince as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredProvince = array as! [Province]
}
However nothing is getting returned when I'm searching. And I tried to do it in this way:
filteredFamily = searchText.isEmpty ? family : family.filter({(dataString: String) -> Bool in
return dataString.rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
})
But, I'm receiving the following error: 'Family is not a subtype of String'. Is there any better way to filter the Family? Because, the filtered result has to be sent back to searchDisplayController.
Thanks in advance.
So we have a Family class that does look like this right?
class Family {
let name : String
init(name:String) {
self.name = name
}
}
Then we have a list of families:
var families = [Family]()
And we want to extract all the families where the name property contains a given text.
let searchText = "something here"
Good, first of all we add this extension to the String struct.
extension String {
func contains(find: String) -> Bool {
return self.rangeOfString(find) != nil
}
}
And finally we can filter the families writing:
let filtered = families.filter { $0.name.contains(searchText) }
Hope this helps.
I have a dictionary of objects and what I would like to do is go through the data set and return an array of objects that conform to a given protocol. I am having issues with the syntax for passing in a desired protocol:
func getObjectsThatConformTo<T>(conformance: T.Type) -> [AnyClass]{
var returnArray: [AnyClass] = []
for(myKey, myValue) in allCreatedObjects{
if let conformantObject = myValue as? conformance{
returnArray.append(conformantObject)
}
return returnArray
}
The error I am seeing is 'conformance' is not a type
Thank you for your help and time
I think this should work:
func getObjectsThatConformToType<T>(type:T.Type) -> [T]{
var returnArray: [T] = []
for(myKey, myValue) in allCreatedObjects{
if let comformantModule = myValue as? T {
returnArray.append(comformantModule)
}
}
return returnArray
}
While you could write a generic-ed method that filters through an array and sees which things in the array are a given type, this problem screams for the use of filter.
Example:
var dict: [String: AnyObject] = [:]
// Populate dict with some values
let strings = dict.values.filter { return $0 is String }
Wrapped in a function that takes type:
func getObjectsThatConformTo<T>(array: [Any], conformance: T.Type) -> [T]? {
return array.filter { return $0 is T } as? [T]
}
Explanation:
Filter is a method on Array which returns a subset of the array based on a test. In this case our test is 'is the element a String?' the filter method accepts a closure with one parameter, the element to be tested, above referred to with $0.
Read up on filter here: https://www.weheartswift.com/higher-order-functions-map-filter-reduce-and-more/
On the process of exploring Core Data with Swift I have the following function working, as a test:
func insertObject (entityName:String) {
var newItem = NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext:managedObjectContext!) as! EventList
let now = NSDate()
newItem.date = now
newItem.eventDescription = “Whatever Anniversary"
}
This seems to work, but to make my function more useful, I want to pass it a dictionnary describing the object I intend to insert.
Something like the following:
func insertObject (entityName:String,dico:NSDictionary) {
var newItem = NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext:managedObjectContext!) as! EventList
for (key, value) in dico {
println("\(key) : \(value)")
newItem.key = value
}
}
Here comes the problem, this line is wrong:
newItem.key = value
What is the proper syntax to use?
This line shows me that the looping part works fine:
println("\(key) : \(value)")
You can use Key-Value coding for managed objects:
func insertObject (entityName:String, dico: [String : NSObject]) {
let newItem = NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext:managedObjectContext!) as! EventList
for (key, value) in dico {
newItem.setValue(value, forKey: key)
}
}
which can be shortened to
func insertObject (entityName:String, dico: [String : NSObject]) {
let newItem = NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext:managedObjectContext!) as! EventList
newItem.setValuesForKeysWithDictionary(dico)
}
The problem with this general approach is that it will crash at
runtime if the dictionary contains keys which are not properties
of the entity, or if the data type does not match.