Search code examples
iosswiftdictionaryswift5

compactMapValues not filtering nil values


compactMapValues on a dictionary returns dictionary with the nil values.

I am using the method as suggested by most of the documentation out there. compactMapValues { $0 }

extension Dictionary where Key == RequestParameter {

    func nilFiltered() -> [RequestParameter: Any] {
        return compactMapValues { $0 }
    }

}

RequestParameter is a enum and I am calling the method like..

[RequestParameter.param1: "value1", RequestParameter.param2: nil]. nilFiltered()

The necessary filtering is not happening. Is this is a known bug or am I doing something wrong?


Solution

  • If you just return $0, that adds a level of optionality The return value of

    [RequestParameter.param1: "value1", .param2: nil]
    

    is a [RequestParameter: String?], which introduces double-optionality. Either do this:

    extension Dictionary {
      func nilFiltered<Wrapped>() -> [Key: Any] where Value == Wrapped? {
        compactMapValues { $0 }
      }
    }
    

    or if you don't actually need Any, avoid that rubbish!

    extension Dictionary {
      func nilFiltered<Wrapped>() -> [Key: Wrapped] where Value == Wrapped? {
        compactMapValues { $0 }
      }
    }
    

    Here's an alternative that I don't like.

    extension Dictionary {
      func nilFiltered() -> [Key: Any] {
        compactMapValues {
          if case nil as Value? = $0 {
            return nil
          }
    
          return $0
        }
      }
    }