简体   繁体   中英

How to filter an array of dictionaries in Swift

I have chosen to populate an NSTableview by using a mutable array of dictionary objects where the dictionary key is the column identifier and the value is the column value. I populate the array like this:

var compArray: NSMutableArray = []

let dict = ["idCompany": id, "company": companyName, "compType": 
companyType] as [String : Any]
            compArray.add(dict)

id, company and compType come from an SQlite query.

I use compArray as the tableView data source. This works great. There is no array controller involved.

Table is loaded as follows using CDM which is an instance of the class that delivers the compArray

//Define the function that will get the data for each cell for each 
//row.
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {

    //Define constant dict as an NSDictionary and set to the DM 
    //instance of the DataModel class at the row being loaded into the 
    //table. DM needs to be cast as an NSDictionary. row is passed in as a 
    //parameter by the OS
    let tdict:NSDictionary = CDM.compArray[row] as! NSDictionary

    //Define strKey as the column identifier for the column being 
    //loaded. Column being loaded is passed in as a parameter by the OS
    let strKey = (tableColumn?.identifier)!

    //method will return the value from dict (which is loaded from 
    //CDM.compArray) for the key that is equal to the column identifier 
    //which was loaded to strKey
    return tdict.value(forKey: strKey.rawValue)
}

What I would like to do is introduce an NSSearch field to search all the columns of the tableview.

I added the searchfield as an action and I also added code to store compArray into a copy called backupCompArray.

I defined an isSearching variable:

//The variable is set to true when searching
var isSearching = false {
    //This will be fired if the state of isSearching changes ie false 
    //to true or true to false
    didSet {

        //Test to see whether isSearching now has a new value and if 
        //so we do the housekeeping
        if isSearching != oldValue {

            //If isSearching is now true then it must have previously 
            //been false and we now need to back up the original array
            if isSearching {
                //Back up the original array
                backUpCompArray = compArray
            } else{
                //It is now turning from true to false so need to 
//restore
                compArray = backUpCompArray
            }
        }
    }
}

I want to be able to filter compArray based on the .stringValue of the searchfield.

I have put the following in the @IBAction of the searchfield:

@IBAction func searchField(_ sender: NSSearchFieldCell) {
    if sender.stringValue.isEmpty {
        //If stringValue is empty then cant be searching and this can 
        //trigger the restore of the original array
        isSearching = false
    } else {

        //If stringValue is not empty then must be searching. When the 
        //search starts need to backup the original array
        isSearching = true

        //?????????????
        }
    }

    tableView.reloadData()
}

I need to replace the ? with code that can set compArray by applying a filter to backupCompArray returning any rows to compArray where the dictionary values for keys "company" and "compType" contains the searchfield.Stringvalue. I can then use the modified compArray to load the table with only filtered rows.

So I tried your code and got two errors that I tried to fix as follows:

//Can use the .filter method it will iterate each value in the array
        CDM.compArray = backupCompArray.filter(using: {
            // this is where you determine whether to include the 
specific element, $0
            $0["company"]!.contains(sender.stringValue) &&
            $0["compType"]!.contains(sender.stringValue)
            // or whatever search method you're using instead
        })
    }

That is inserting 'using' and changing searchString to sender.Stringvalue.

But I now get: 在此处输入图片说明

against the line that ends with &&

You can do this with Swift 4's Array.filter() . It takes a function where you can do your computation. You actually shouldn't need to back up your compArray, unless you need to keep it around later for something else.

compArray = compArray.filter({
    // this is where you determine whether to include the specific element, $0
    $0["company"]!.contains(searchString) &&
    $0["compType"]!.contains(searchString)
    // or whatever search method you're using instead
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM