问题描述:

i am trying to filter a dictionary in swift:

var data: [String: String] = [:]

data = data.filter { $0.1 == "Test" }

the filter code above compiles under swift 2 but yields the following error:

Cannot assign a value of type '[(String, String)]' to a value of type '[String : String]'

is this a bug in the swift compiler or is this not the right way to filter dictionaries in swift?

Thank you very much in advance!

网友答案:

The problem is that data is a dictionary but the result of filter is an array, so the error message says that you can't assign the result of the latter to the former.

You could just create a new variable/constant for your resulting array:

let data: [String: String] = [:]
let filtered = data.filter { $0.1 == "Test" }

Here filtered is an array of tuples: [(String, String)].

Once filtered, you can recreate a new dictionary if this is what you need:

var newData = [String:String]()
for result in filtered {
    newData[result.0] = result.1
}

If you decide not to use filter you could mutate your original dictionary or a copy of it:

var data = ["a":"Test", "b":"nope"]
for (key, value) in data {
    if value != "Test" {
        data.removeValueForKey(key)
    }
}
print(data) // ["a": "Test"]

Note: in Swift 3, removeValueForKey has been renamed removeValue(forKey:), so in this example it becomes data.removeValue(forKey: key).

网友答案:
data.forEach { if $1 != "Test" { data[$0] = nil } }

Just another approach (a bit simplified) to filter out objects in your dictionary.

网友答案:

Per Apple docs, filter:

Returns an array containing, in order, the elements of the sequence that satisfy the given predicate.

https://developer.apple.com/reference/swift/sequence/1641239-filter

I found myself needing to do what the OP was asking about and ended up writing the following extensions (Swift 3):

extension Dictionary
{
  func filteredDictionary(_ isIncluded: (Key, Value) -> Bool)  -> Dictionary<Key, Value>
  {
    return self.filter(isIncluded).toDictionary(byTransforming: { $0 })
  }
}

extension Array
{
  func toDictionary<H:Hashable, T>(byTransforming transformer: (Element) -> (H, T)) -> Dictionary<H, T>
  {
    var result = Dictionary<H,T>()
    self.forEach({ element in
      let (key,value) = transformer(element)
      result[key] = value
    })
    return result
  }
}

Usage:

let data = ["a":"yes", "b":"nope", "c":"oui", "d":"nyet"]
let filtered = data.filteredDictionary({ $0.1 >= "o" })

// filtered will be a dictionary containing ["a": "yes", "c": "oui"]
相关阅读:
Top