Swift filter dictionary error: Cannot assign a value of type '[(_, _)]' to a value of type '[_ : _]'

Solution 1:

This has been fixed in Swift 4

let data = ["a": 0, "b": 42]
let filtered = data.filter { $0.value > 10 }
print(filtered) // ["b": 42]

In Swift 4, a filtered dictionary returns a dictionary.


Original answer for Swift 2 and 3

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).

Solution 2:

data.forEach { if $1 != "Test" { data[$0] = nil } }

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

Solution 3:

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"]