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

IosSwift

Ios Problem Overview


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?

Ios Solutions


Solution 1 - Ios

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 - Ios

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

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

Solution 3 - Ios

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

Solution 4 - Ios

I've found this method to be useful after filtering or applying some other transform that results in an array of dictionary elements:

extension Array {
    func dictionary<K: Hashable, V>() -> [K: V] where Element == Dictionary<K, V>.Element {
        var dictionary = [K: V]()
        for element in self {
            dictionary[element.key] = element.value
        }
        return dictionary
    }
}

To use it, just say something like:

dictionary = dictionary.filter{ $0.key == "test" }.dictionary()

The advantage of this method is that no argument of any kind needs to be passed to the dictionary() method. Generic type arguments tell the compiler everything it needs to know.

Solution 5 - Ios

You can arrange ascending order according to dictionary value using filter

let arrOfDict = [{"ABC":24},{"XYZ":21},{"AAA":23}]

let orderedDict = arrOfDict.filter{$0.value < $1.value}

you will get below output:

[  { "XYZ": 21 },   { "AAA": 23 },   { "ABC": 24 }]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionwarlyView Question on Stackoverflow
Solution 1 - IosEric AyaView Answer on Stackoverflow
Solution 2 - IosEendjeView Answer on Stackoverflow
Solution 3 - Iosuser7367341View Answer on Stackoverflow
Solution 4 - IosGregory HigleyView Answer on Stackoverflow
Solution 5 - IosHitesh RasalView Answer on Stackoverflow