Search code examples
arraysswiftdictionarygroupinginitializer

Dictionary(grouping: , by: ) - predicate closure passed as a variable


I'm interested in using Dictionary(grouping: , by: ) initializer. However, I have to group items based on a different key, depending on circumstances. How can I conditionally select the key and then pass it as a variable to the by: argument?

let predicate: ((MyObjectType) -> Int?)
if shouldUseValue1 {
    predicate = {$0.value1?.intValue}
} else {
    predicate = {$0.value2?.intValue}
}

var grouped = Dictionary(grouping: arrayToGroup, by: predicate)

The error I'm getting is:

Cannot convert value of type '(MyObjectType) -> Int?' to expected argument type '(_) -> _'

So, the question is what type should I pass to the by: argument of the initializer to make it work?


Solution

  • I've just been playing around with this in a Playground and came up with this working code:

    let array: [String] = ["Ho", "Hi", "Hello", "Hola", "Bonjour"]
    let pred: (String) -> String.Element?
    
    if true {
        pred = { $0.first }
    } else {
        pred = { $0.last }
    }
    
    var grouped = Dictionary(grouping: array, by: pred)
    print(grouped)
    

    So the by parameter expects a value of the same type in the array .Element. e.g. String.Element.

    You could of also done:

    let array: [String] = ["Ho", "Hi", "Hello", "Hola", "Bonjour"]
    let pred: (String) -> String.Element? = { true ? $0.first : $0.last }
    
    var grouped = Dictionary(grouping: array, by: pred)
    print(grouped)
    

    Note: Stating the obvious but I am using true instead of a real condition.