Reputation: 5371
I would like to get the opposite of a boolean value using dot syntax.
E.g.
let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(!digitsExceptForFive.contains)
// Cannot convert value of type '(Int) -> Bool' to expected argument type 'Bool'
The following code works, however.
let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let notFives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(digitsExceptForFive.contains)
// [1, 2, 3, 4, 6, 7, 8, 9]
I need to get the opposite value functionally using the not operator. If it's possible I would like not to have to define a bool extension or custom operator just to do so.
How can you do this in Swift?
Upvotes: 0
Views: 291
Reputation: 236340
I would just extend Sequence
protocol constraining Element
to Equatable
and implement a notContains
method:
extension Sequence where Element: Equatable {
func notContains(_ element: Element) -> Bool { !contains(element) }
}
let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(digitsExceptForFive.notContains) // [5]
You can also extend Bool and
provide a negated
property, this would allow to use negated KeyPath
syntax:
extension Bool {
var negated: Bool { !self }
}
let string = "abc12345"
let nonDigits = string.filter(\.isWholeNumber.negated) // "abc"
if you really want to implement a custom prefix operator (I really prefer using the notConstains method and the Bool negated instance property) you can do something like:
prefix func !<T>(predicate: @escaping (T) -> Bool) -> (T) -> Bool { { !predicate($0) } }
Usage:
let string = "abc12345"
let nonDigits = string.filter(!\.isWholeNumber) // "abc"
let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(!digitsExceptForFive.contains) // [5]
Upvotes: 2
Reputation: 5371
This language support needs to be added to Swift for ergonomic semantics. Please refer to the evolution pitch discussion on the Swift Evolution forums.
Upvotes: 0
Reputation: 385580
I guess you want to write something like digitsExceptForFive.contains.not
.
Sadly, you can't, because that would require the type (Int) -> Bool
to have a not
method. Functions cannot have methods.
You could write an overload of operator !
to do it (letting your first attempt work), but I wouldn't recommend it. Operator overloads tend to slow down compile times and confuse later readers of the code.
I recommend you just write it this way:
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter { !digitsExceptForFive.contains($0) }
Upvotes: 1