Last active
April 19, 2024 18:35
-
-
Save jpmhouston/72eb8e6681b7cc2499ca1c350b5f0c09 to your computer and use it in GitHub Desktop.
Swift methods implementing the inverse of contains()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Insired by https://forums.swift.org/t/iscontained-in-array-extension-of-equatable/20223/28 | |
// Exercise for the reader: define operators ∈ and ∉ | |
// | |
// Created primarily for excluded, which I wanted to use in an | |
// expression like: | |
// `let foos = things.compactMap({ $0.foo?.excluded(from: [a,b,c]) })` | |
// I then went on to generalize to included(in:) and all the | |
// variations below, and found an even better way to write similar | |
// expressions: `let x = y.excluding([u,v,w])` | |
// | |
// Note, I had to add the subtle variant of these functions when | |
// a,b,c are optionals of foo's type so that it wouldn't fail with | |
// "Cannot convert value of type 'Foo?' to expected element type 'Foo'". | |
// Before adding those variants I instead needed an expression like: | |
// `compactMap({ $0.foo?.excludedFrom([a,b,c].compactMap({$0})) })` | |
// | |
// I then added inverse of Range.contains(), which I thought was best | |
// named like inside(range r:), outside(range r:) | |
// | |
public extension Equatable { | |
func isIncluded<S: Sequence>(in s: S) -> Bool where S.Element == Self { | |
s.contains(self) | |
} | |
func isIncluded<S: Sequence>(in s: S) -> Bool where S.Element == Self? { | |
s.contains(self) | |
} | |
func isIncluded(in s: Self...) -> Bool { | |
s.contains(self) | |
} | |
func isIncluded(in s: Self?...) -> Bool { | |
s.contains(self) | |
} | |
func isExcluded<S: Sequence>(in s: S) -> Bool where S.Element == Self { | |
!s.contains(self) | |
} | |
func isExcluded<S: Sequence>(in s: S) -> Bool where S.Element == Self? { | |
!s.contains(self) | |
} | |
func isExcluded(in s: Self...) -> Bool { | |
!s.contains(self) | |
} | |
func isExcluded(in s: Self?...) -> Bool { | |
!s.contains(self) | |
} | |
func included<S: Sequence>(in s: S) -> Self? where S.Element == Self { | |
s.contains(self) ? self : nil | |
} | |
func included<S: Sequence>(in s: S) -> Self? where S.Element == Self? { | |
s.contains(self) ? self : nil | |
} | |
func included(in s: Self...) -> Self? { | |
s.contains(self) ? self : nil | |
} | |
func included(in s: Self?...) -> Self? { | |
s.contains(self) ? self : nil | |
} | |
func excluded<S: Sequence>(from s: S) -> Self? where S.Element == Self { | |
s.contains(self) ? nil : self | |
} | |
func excluded<S: Sequence>(from s: S) -> Self? where S.Element == Self? { | |
s.contains(self) ? nil : self | |
} | |
func excluded(from s: Self...) -> Self? { | |
s.contains(self) ? nil : self | |
} | |
func excluded(from s: Self?...) -> Self? { | |
s.contains(self) ? nil : self | |
} | |
} | |
// oh, maybe these are just other names for intersection, subtract :shrug: | |
// maybe find another variation that better describes which is iterated over | |
// and which is more optimal to call contains on, self or the parameter | |
public extension Sequence where Element: Equatable { | |
func includes<S: Sequence>(_ s: S) -> Bool where S.Element == Element { | |
contains { s.contains($0) } | |
} | |
func includes<S: Sequence>(_ s: S) -> Bool where S.Element == Element? { | |
contains { s.contains($0) } | |
} | |
func includes(_ s: Element...) -> Bool { | |
contains { s.contains($0) } | |
} | |
func includes(_ s: Element?...) -> Bool { | |
contains { s.contains($0) } | |
} | |
func excludes<S: Sequence>(_ s: S) -> Bool where S.Element == Element { | |
contains { !s.contains($0) } | |
} | |
func excludes<S: Sequence>(_ s: S) -> Bool where S.Element == Element? { | |
contains { !s.contains($0) } | |
} | |
func excludes(_ s: Element...) -> Bool { | |
contains { !s.contains($0) } | |
} | |
func excludes(_ s: Element?...) -> Bool { | |
contains { !s.contains($0) } | |
} | |
func including<S: Sequence>(_ s: S) -> some Sequence<Element> where S.Element == Element { | |
filter { s.contains($0) } | |
} | |
func including<S: Sequence>(_ s: S) -> some Sequence<Element> where S.Element == Element? { | |
filter { s.contains($0) } | |
} | |
func including(_ s: Element...) -> some Sequence<Element> { | |
filter { s.contains($0) } | |
} | |
func including(_ s: Element?...) -> some Sequence<Element> { | |
filter { s.contains($0) } | |
} | |
func excluding<S: Sequence>(_ s: S) -> some Sequence<Element> where S.Element == Element { | |
filter { !s.contains($0) } | |
} | |
func excluding<S: Sequence>(_ s: S) -> some Sequence<Element> where S.Element == Element? { | |
filter { !s.contains($0) } | |
} | |
func excluding(_ s: Element...) -> some Sequence<Element> { | |
filter { !s.contains($0) } | |
} | |
func excluding(_ s: Element?...) -> some Sequence<Element> { | |
filter { !s.contains($0) } | |
} | |
} | |
public extension Comparable { | |
func isInside(range r: Range<Self>) -> Bool { | |
r.contains(self) | |
} | |
func isInside(range r: ClosedRange<Self>) -> Bool { | |
r.contains(self) | |
} | |
func isOutside(range r: Range<Self>) -> Bool { | |
!r.contains(self) | |
} | |
func isOutside(range r: ClosedRange<Self>) -> Bool { | |
!r.contains(self) | |
} | |
func inside(range r: Range<Self>) -> Self? { | |
r.contains(self) ? self : nil | |
} | |
func inside(range r: ClosedRange<Self>) -> Self? { | |
r.contains(self) ? self : nil | |
} | |
func outside(range r: Range<Self>) -> Self? { | |
r.contains(self) ? nil : self | |
} | |
func outside(range r: ClosedRange<Self>) -> Self? { | |
r.contains(self) ? nil : self | |
} | |
} | |
public extension Sequence where Element: Comparable { | |
func thoseInside<S: Sequence>(range r: Range<Element>) -> some Sequence<Element> where S.Element == Element { | |
filter { r.contains($0) } | |
} | |
func thoseInside<S: Sequence>(range r: ClosedRange<Element>) -> some Sequence<Element> where S.Element == Element { | |
filter { r.contains($0) } | |
} | |
func thoseOutside<S: Sequence>(range r: Range<Element>) -> some Sequence<Element> where S.Element == Element { | |
filter { !r.contains($0) } | |
} | |
func thoseOutside<S: Sequence>(range r: ClosedRange<Element>) -> some Sequence<Element> where S.Element == Element { | |
filter { !r.contains($0) } | |
} | |
} | |
/* | |
let evenDigits = [0,2,4,6,8] | |
let oddDigits = [1,3,5,7,9] | |
let evenDigitsSet = Set([0,2,4,6,8]) | |
let oddDigitsSet = Set([1,3,5,7,9]) | |
print("1 is even: \(1.isIncludedIn(evenDigits))") // 1 is even: false | |
print("2 is even: \(2.isIncludedIn(evenDigitsSet))") // 2 is even: true | |
print("3 is odd: \(3.isIncludedIn(1,3,5,7,9))") // 3 is odd: true | |
print("4 is odd: \(4.isIncludedIn(1,3,5,7,9))") // 4 is odd: false | |
print("even: \([1,2,3,4].compactMap { $0.includedIn(evenDigits) })") // even: [2, 4] | |
print("odd: \([1,2,3,4].compactMap { $0.excludedFrom(evenDigitsSet) })") // odd: [1, 3] | |
print("even: \([3,4,5,6].excluding(oddDigitsSet))") // even: [4, 6] | |
print("odd: \([3,4,5,6].including(oddDigits))") // odd: [3, 5] | |
print("even: \([6,7,8,9].including(0,2,4,6,8))") // even: [6, 8] | |
print("odd: \([6,7,8,9].excluding(0,2,4,6,8))") // odd: [7, 9] | |
(hmm those don't exercise the overloads with optionals) | |
*/ | |
/* | |
i named them like this originally: | |
file Equatable+IsIn.swift | |
public extension Equatable { | |
func isIn<S: Sequence>(_ s: S) -> Bool where S.Element == Self { | |
s.contains(self) | |
} | |
func isNotIn<S: Sequence>(_ s: S) -> Bool where S.Element == Self { | |
!s.contains(self) | |
} | |
func onlyIfIn<S: Sequence>(_ s: S) -> Self? where S.Element == Self { | |
s.contains(self) ? self : nil | |
} | |
func onlyIfNotIn<S: Sequence>(_ s: S) -> Self? where S.Element == Self { // got suggestion to rename this unlessIn | |
s.contains(self) ? nil : self | |
} | |
func isIn(_ s: Self...) -> Bool { | |
s.contains(self) | |
} | |
func isNotIn(_ s: Self...) -> Bool { | |
!s.contains(self) | |
} | |
func onlyIfIn(_ s: Self...) -> Self? { | |
s.contains(self) ? self : nil | |
} | |
func onlyIfNotIn(_ s: Self...) -> Self? { // got suggestion to rename this unlessIn | |
s.contains(self) ? nil : self | |
} | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment