Generic next() and previous() method for CaseItearble - swift

Suppose we have an enum and want to enumerate over it :).
If it has Int rawValue we can be provided with next and previous items using computed vars like this.
enum Fidelity: Int, CaseIterable {
case pixel
case point
case average
case datapoint
var previousFidelity: Fidelity {
return Fidelity(rawValue: rawValue - 1) ?? .pixel
}
var nextFidelity: Fidelity {
return Fidelity(rawValue: rawValue + 1) ?? .datapoint
}
}
I went further and created and extension for CaseIterable which allows next() and previous() for a wide range of types.
// Let's test Swift 4.2 for enumerating enum
// Too complex, not very efficient, but interesting
extension CaseIterable where Self: Equatable {
func next() -> Self? {
let all = Self.allCases
let idx = all.index(of: self)!
let next = all.index(after: idx)
return (next == all.endIndex) ? nil : all[next]
}
func previous() -> Self? {
let all_reversed = Self.allCases.reversed()
let idx = all_reversed.index(of: self)!
let next = all_reversed.index(after: idx)
return (next == all_reversed.endIndex) ? nil : all_reversed[next]
}
}
The question is how efficient or inefficient my solutions are (i.e. speed, memory)?
Are there any ideas for doing the same or similar things, perhaps offset(by: ).

You can implement previous() using offsetBy this way:
func previous() -> Self? {
let all = Self.allCases
var idx = all.index(of: self)!
if idx == all.startIndex {
return nil
} else {
all.formIndex(&idx, offsetBy: -1)
return all[idx]
}
}
You can combine both next() and previous() in a more generic offset function:
extension CaseIterable where Self: Equatable {
func advanced(by n: Int) -> Self? {
let all = Self.allCases
let idx = all.index(of: self)!
//An enum with a raw type has at least one case
let lastIndex = all.index(all.endIndex, offsetBy: -1)
let limit = n > 0 ? lastIndex : all.startIndex
if let newIndex = all.index(idx, offsetBy: n, limitedBy: limit) {
return all[newIndex]
} else {
return nil
}
}
}
And use it like so
let average = Fidelity.average //average
average.advanced(by: 1) //datapoint
average.advanced(by: 2) //nil
average.advanced(by: -3) //pixel

Related

Type 'MatchedValue' does not conform to protocol 'Decodable'

I have a struct that must conform to Codable protocol.
However, I get the error:
Type 'MatchedValue' does not conform to protocol 'Decodable'**
How can I make String.Index conform to Codable?
Thanks
struct MatchedValue: Codable {
let value: String
let range: Range<String.Index>
}
Try using Int instead of String.Index.
First, extensions to get the position of an element or string as Int and the ability to use integer ranges:
extension StringProtocol {
func distance(of element: Element) -> Int? { firstIndex(of: element)?.distance(in: self) }
func distance<S: StringProtocol>(of string: S) -> Int? { range(of: string)?.lowerBound.distance(in: self) }
func substring(with range: Range<Int>) -> String? {
guard range.lowerBound >= 0 && range.upperBound <= self.count else { return nil }
let lowerBoundStringIndex = self.index(self.startIndex, offsetBy: range.lowerBound)
let upperBoundStringIndex = self.index(lowerBoundStringIndex, offsetBy: range.upperBound - range.lowerBound)
return String(self[lowerBoundStringIndex..<upperBoundStringIndex])
}
subscript(r: Range<Int>) -> String? { substring(with: r) }
func substring(with range: ClosedRange<Int>) -> String? {
guard range.lowerBound >= 0 && range.upperBound < self.count else { return nil }
if range.lowerBound == range.upperBound { return "" }
let lowerBoundStringIndex = self.index(self.startIndex, offsetBy: range.lowerBound)
let upperBoundStringIndex = self.index(lowerBoundStringIndex, offsetBy: range.upperBound + 1 - range.lowerBound)
return String(self[lowerBoundStringIndex..<upperBoundStringIndex])
}
subscript(r: ClosedRange<Int>) -> String? { substring(with: r) }
}
extension Collection {
func distance(to index: Index) -> Int { distance(from: startIndex, to: index) }
}
extension String.Index {
func distance<S: StringProtocol>(in string: S) -> Int { string.distance(to: self) }
}
Now you can use this new implementation:
let letters = "My string"
letters.count // 9
// get range
let lowerBound: Int? = letters.distance(of: "M")
let upperBound: Int? = letters.distance(of: "g")
let intRange: Range<Int> = lowerBound!..<upperBound!
let intClosedRange: ClosedRange<Int> = lowerBound!...upperBound!
// get substring
letters.substring(with: intRange) // "My strin"
letters.substring(with: intClosedRange) // "My string"
// or
letters[intRange] // "My strin"
letters[intClosedRange] // "My string"
I also include a comparison using String.Index and other tests.
// For comparison purposes only
let lowerIndex = letters.firstIndex(of: "M")
let upperIndex = letters.firstIndex(of: "g")
let range: Range<String.Index> = lowerIndex!..<upperIndex!
let closedRange: ClosedRange<String.Index> = lowerIndex!...upperIndex!
letters[range] // "My strin"
letters[closedRange] // "My string"
// Additional implementation tests
letters.substring(with: 3...5) // "str"
letters.substring(with: 3..<5) // "st"
letters.substring(with: 0...9) // nil
letters.substring(with: 0..<9) // "My string"
letters.substring(with: 2...2) // ""
letters.substring(with: 2..<2) // ""
Here is my
gist.

How to implement a 'next' property to a CaseIterable enum in Swift

I'm trying to add a next var to an enum. I am able to do so for a specific enum but would like to extend it generically so that I can obtain the 'next' enum case from an enum value just by specifying an enum with a protocol, ex CaseNextIterable
enum MyEnum: CaseIterable { // 'next' here is possible thanks to 'CaseIterable' protocol
case a, b, c
// returns the next case, or first if at end of sequence
// ie. a.next == b, c.next == a
var next: Self {
var r: Self!
for c in Self.allCases + Self.allCases { // not efficient
if r != nil {
r = c
break
}
if c == self {
r = self
}
}
return r
}
}
You can extend CaseIterable constraining Self to Equatable. Then you just need to find the index after the firstIndex of your CaseItareble enumeration and return the element at that position. If the index is equal to the endIndex of all cases just return the first element.
extension CaseIterable where Self: Equatable {
private var allCases: AllCases { Self.allCases }
var next: Self {
let index = allCases.index(after: allCases.firstIndex(of: self)!)
guard index != allCases.endIndex else { return allCases.first! }
return allCases[index]
}
}
Another option is to constrain AllCases to BidirectionalCollection. This will allow you to get the last element of you enumeration, check if it is equal to self and return the first element without the need to iterate your whole collection:
extension CaseIterable where Self: Equatable, AllCases: BidirectionalCollection {
var allCases: AllCases { Self.allCases }
var next: Self {
guard allCases.last != self else { return allCases.first! }
return allCases[allCases.index(after: allCases.firstIndex(of: self)!)]
}
}
expanding on CaseIterable next and previous properties:
extension CaseIterable {
typealias Index = AllCases.Index
var first: Self { allCases.first! }
private var allCases: AllCases { Self.allCases }
private static func index(after i: Index) -> Index { allCases.index(after: i) }
}
extension CaseIterable where AllCases: BidirectionalCollection {
var last: Self { allCases.last! }
private static func index(before i: Index) -> Index { allCases.index(before: i) }
}
extension CaseIterable where Self: Equatable {
var index: Index { Self.firstIndex(of: self) }
private static func firstIndex(of element: Self) -> Index { allCases.firstIndex(of: element)! }
}
extension CaseIterable where Self: Equatable, AllCases: BidirectionalCollection {
var previous: Self { first == self ? last : allCases[Self.index(before: index)] }
var next: Self { last == self ? first : allCases[Self.index(after: index)] }
}
Playground testing;
enum Enum: CaseIterable {
case a,b,c
}
let value: Enum = .c
let next = value.next // a
let next2 = next.next // b
let next3 = next2.next // c
let previous = value.previous // b
let previous2 = previous.previous // a
let previous3 = previous2.previous // c
I'm adding this in complement of Leo Dabus' answer, in case people would need the previous extension too.
edit:
I added both next and previous.
The main difference is in the behavior expected.
For out of band:
this solution returns nul
Leo Dabus' solution works like a chained list
extension CaseIterable where Self: Equatable {
var allCases: AllCases { Self.allCases }
/// Using `next` on an empty enum of on the last element returns `nil`
var next: Self? {
guard let currentIndex = allCases.firstIndex(of: self) else { return nil }
let index = allCases.index(after: currentIndex)
// ensure we don't go past the last element
guard index != allCases.endIndex else { return nil }
return allCases[index]
}
var previous: Self? {
guard let currentIndex = allCases.firstIndex(of: self) else { return nil }
// ensure we don't go before the first element
guard currentIndex != allCases.startIndex else { return nil }
let index = allCases.index(currentIndex, offsetBy: -1)
return allCases[index]
}
}

Init a FloatingPoint from a string

I am trying to convert a 2d array of Strings into my custom generic type Matrix:
func convert(_ arr: [[String]]) -> Matrix<Element> {
var m: Matrix<Element> = Matrix()
for row in arr {
var v: [Element] = []
for e in row {
let convE: Element = Element(string: e) // right here I'd like to implement something like that: Element(string: e)
v.append(convE)
}
m.vectors.append(Vector(v))
}
return m
}
The Matrix.Element does conform to the FloatingPoint protocol. Please tell me if you wish to see the Matrix struct but I think I haven't implemented anything that's important for this question other than that the generic Element type of Matrix does conform to the FloatingPoint protocol.
My problem is I want Element to be something like Float, Double... (any of the FloatingPoint types) but how can I initialize a FloatingPoint from a string? I tried:
extension FloatingPoint {
init(string: String) {
self.init(Int(string)!)
}
}
which obviously only works for strings like "1", "2"... and not "1.2", "3.541" and so on which I want.
Edit:(#Leo Dabus)
protocol DArray: Sequence {
associatedtype Component: FloatingPoint
}
extension DArray {
static func * <T: DArray>(lhs: Self, rhs: T) -> Vector<Component> {
let v = lhs as? Vector<Component> ?? rhs as! Vector<Component>
let m = lhs as? Matrix<Component> ?? rhs as! Matrix<Component>
return Vector(m.map { zip(v, $0).map(*).reduce(0, +) })
}
static func / <T: DArray>(lhs: Self, rhs: T) -> Vector<Component> {
let v = lhs as? Vector<Component> ?? lhs as! Vector<Component>
let m = lhs as? Matrix<Component> ?? lhs as! Matrix<Component>
return Vector(m.map { zip(v, $0).map(/).reduce(0, +) })
}
}
struct Vector<Component: FloatingPoint>: DArray {
var components: [Component]
var count: Int {
return components.count
}
init(_ Components: [Component] = []) {
self.components = Components
}
subscript(i: Int) -> Component {
get {
return components[i]
} set {
components[i] = newValue
}
}
static func + (lhs: Self, rhs: Self) -> Self {
return Vector(zip(lhs, rhs).map(+))
}
static func - (lhs: Self, rhs: Self) -> Self {
return Vector(zip(lhs, rhs).map(-))
}
static func * (lhs: Self, rhs: Self) -> Self {
return Vector(zip(lhs, rhs).map(*))
}
static func / (lhs: Self, rhs: Self) -> Self {
return Vector(zip(lhs, rhs).map(/))
}
func empty(of length: Int) -> Self {
return Vector(Array(repeating: 0, count: length))
}
}
struct Matrix<Component: FloatingPoint>: DArray {
var vectors: [Vector<Component>]
var nRows: Int {
return vectors.count
}
var nColumns: Int {
guard !vectors.isEmpty else { return 0 }
return vectors[0].count
}
var count: Int {
return vectors.count
}
init(_ vectors: [Vector<Component>] = []) {
self.vectors = vectors
}
subscript(r: Int) -> Vector<Component> {
get {
return vectors[r]
}
set {
vectors[r] = newValue
}
}
subscript(r: Int, c: Int) -> Component {
get {
return vectors[r][c]
}
set {
vectors[r][c] = newValue
}
}
}
Additionally I have my two structs conform to the Sequence protocol.
(Note: I am the OP)
What I came up with now is:
extension FloatingPoint {
public init?(string: String) {
if Self.self == Double.self {
self = Double(string) as! Self
} else if Self.self == Float.self {
self = Float(string) as! Self
} else if Self.self == Float80.self {
self = Float80(string) as! Self
} else {
return nil
}
}
}
It works for my use case but I was wondering whether it is a good way of achieving what I am looking for. So I'd be happy for someone to evaluate my solution. (#Leo Dabus)
You can extend FloatingPoint protocol and constrain the generic type to LosslessStringConvertible:
extension StringProtocol {
func floatingPoint<T: FloatingPoint>() -> T? where T: LosslessStringConvertible {
T(String(self))
}
}
Note that CGFloat does NOT conform to LosslessStringConvertible so you would need to implement a custom String initializer:
extension CGFloat: LosslessStringConvertible {
private static let formatter = NumberFormatter()
public init?(_ description: String) {
guard let number = CGFloat.formatter.number(from: description) as? CGFloat else { return nil }
self = number
}
}
let double: Double? = "2.7".floatingPoint() // 2.7
let float: Float? = "2.7".floatingPoint() // 2.7
let float80: Float80? = "2.7".floatingPoint() // 2.7
let cgfloat: CGFloat? = "2.7".floatingPoint() // 2.7
There is already an initializer for FloatingPoint types but to make your code work you need to conform your Matrix Component to LosslessStringConvertible.
Can you try something like this:
extension FloatingPoint where Self == Double {
init(string: String) {
self.init(Double(string)!)
}
}
extension FloatingPoint where Self == Float {
init(string: String) {
self.init(Float(string)!)
}
}
this should work as well
extension FloatingPoint {
init(string: String) {
self.init(Self(string)!)
}
}

Cannot increment beyond endIndex

I'm looking for the "Swift 3" way of handling an error where I try to increment the position of a string to an out of bounds index. I have an extension that looks like the following:
extension String {
func substring(from: Int) -> String {
let fromIndex = index(from: from)
return substring(from: fromIndex)
}
}
In implementation code, I have a loop which periodically takes chunks of a string and moves the index further in the string. My problem is I'm not sure what the Swift 3 way is of handling "End of String, do not proceed if we've reached the end"
Implementation code is something as trivial as this:
myStr = myStr.substring(from: pos + 1)
if pos + 1 is the end of the string, it shouldn't error out, but should instead just exit/return from my loop. What's the best way of doing that?
You can write something like this
extension String {
func substring(from offset: Int) -> String {
let fromIndex = index(self.startIndex, offsetBy: offset)
return substring(from: fromIndex)
}
}
Examples
"Hello world".substring(from: 0) // "Hello world"
"Hello world".substring(from: 1) // "ello world"
"Hello world".substring(from: 2) // "llo world"
What does happen if you pass the wrong param?
Something like this will generate a fatal error.
"Hello world".substring(from: 12)
fatal error: cannot increment beyond endIndex
You can make you code safer adding a guard statement like this
extension String {
func substring(from: Int) -> String? {
guard from < self.characters.count else { return nil }
let fromIndex = index(self.startIndex, offsetBy: from)
return substring(from: fromIndex)
}
}
You can use the index(_, offsetBy:, limitedBy:) method
to ensure that the index is not advanced beyond the end index:
extension String {
func substring(from: Int) -> String? {
guard let fromIndex = index(startIndex, offsetBy: from, limitedBy: endIndex) else {
return nil
}
return substring(from: fromIndex)
}
}
extension String {
func substring(from index: Int) -> String {
guard index < characters.count else { return "" }
return substring(from: characters.index(startIndex, offsetBy: index))
}
}
"12345".substring(from: 3) // "45"
"12345".substring(from: 9) // ""
Alternatively, you might want to return nil if index is out of bounds when you change the function's return type to String?

How to compare "Any" value types

I have several "Any" value types that I want to compare.
var any1: Any = 1
var any2: Any = 1
var any3: Any = "test"
var any4: Any = "test"
print(any1 == any2)
print(any2 == any3)
print(any3 == any4)
Using the == operator shows an error:
"Binary operator '==' cannot be applied to two 'Any' (aka
'protocol<>') operands"
What would be the way to do this ?
The only way to do this is with a function other than == that takes a type parameter, and then compares the values if they are both of that type:
func isEqual<T: Equatable>(type: T.Type, a: Any, b: Any) -> Bool {
guard let a = a as? T, let b = b as? T else { return false }
return a == b
}
Now, using your variables above, you can compare them like this:
var any1: Any = 1
var any2: Any = 1
var any3: Any = "test"
var any4: Any = "test"
isEqual(type: Int.self, a: any1, b: any2) // true
isEqual(type: Int.self, a: any2, b: any3) // false
isEqual(type: String.self, a: any3, b: any4) // true
You can do it like this by using AnyHashable:
func equals(_ x : Any, _ y : Any) -> Bool {
guard x is AnyHashable else { return false }
guard y is AnyHashable else { return false }
return (x as! AnyHashable) == (y as! AnyHashable)
}
print("\(equals(3, 4))") // false
print("\(equals(3, equals))") // false
print("\(equals(3, 3))") // true
As not every Equatable has to be Hashable, this might fail under rare circumstances.
Usually there is no reason for using above hack; but sometimes you will need it, just as sometimes AnyHashable is needed.
To use == operator, type has to conform to Equatable protocol. Any protocol does not conform to Equatable protocol, so there is no way to compare two Any values. It's logical - Any is too broad term - values can have no 'common denominator'.
What's more, Swift doesn't allow to compare two Equatable values which have different type. E.g. both Int and String conform to Equatable but 1 == "1" does not compile. The reason for that is the declaration of == in Equatable protocol: func ==(lhs: Self, rhs: Self) -> Bool. This Self basically means that both arguments have to have the same type. It it's kind of a placeholder - in implementation for specific type, Self should be replaced with the name of this type.
Aaron Rasmussen's answer can also be used as an extension, like so:
public extension Equatable {
/// Equate two values of unknown type.
static func equate(_ any0: Any, _ any1: Any) -> Bool {
guard
let equatable0 = any0 as? Self,
let equatable1 = any1 as? Self
else { return false }
return equatable0 == equatable1
}
}
final class EquatableTestCase: XCTestCase {
func test_equate() {
let int: Any = Int.random( in: .min...(.max) )
let bool: Any = Bool.random()
XCTAssertTrue( Int.equate(int, int) )
XCTAssertTrue( .equate(bool, bool) )
XCTAssertFalse( .equate(int, int) )
XCTAssertTrue( AnyHashable.equate(bool, bool) )
XCTAssertFalse( AnyHashable.equate(bool, int) )
}
}
We can solve it in the following way
enum SwiftDataType
{
case String
case Int
case Int64
case Double
case Bool
case Undefined
}
func getType( of : Any ) -> SwiftDataType
{
if let type = of as? String
{
return SwiftDataType.String
}
else if let type = of as? Int
{
return SwiftDataType.Int
}
else if let type = of as? Int64
{
return SwiftDataType.Int64
}
else if let type = of as? Double
{
return SwiftDataType.Double
}
else if let type = of as? Bool
{
return SwiftDataType.Bool
}
else
{
return SwiftDataType.Undefined
}
}
func isEqual( a : Any, b : Any ) -> Bool
{
let aType : SwiftDataType = getType( of : a )
let bType : SwiftDataType = getType( of : b )
if aType != bType
{
print("Type is not Equal -> \(aType)")
return false
}
else
{
switch aType {
case SwiftDataType.String :
guard let aValue = a as? String, let bValue = b as? String else
{
return false
}
return aValue == bValue
case SwiftDataType.Int :
guard let aValue = a as? Int, let bValue = b as? Int else
{
return false
}
return aValue == bValue
case SwiftDataType.Int64 :
guard let aValue = a as? Int64, let bValue = b as? Int64 else
{
return false
}
return aValue == bValue
case SwiftDataType.Double :
guard let aValue = a as? Double, let bValue = b as? Double else
{
return false
}
return aValue == bValue
case SwiftDataType.Bool :
guard let aValue = a as? Bool, let bValue = b as? Bool else
{
return false
}
return aValue == bValue
default:
return false
}
}
}
You can use NSObject ...
var any1: Any = 1
var any2: Any = 1
var any3: Any = "test"
var any4: Any = "test"
var any5: Any? = nil
var any6: Any? = nil
print(any1 as? NSObject == any2 as? NSObject)
print(any2 as? NSObject == any3 as? NSObject)
print(any3 as? NSObject == any4 as? NSObject)
print(any4 as? NSObject == any5 as? NSObject)
print(any5 as? NSObject == any6 as? NSObject)
This should produce :-
true
false
true
false
true
There is a semi-private function _openExistential, shipped no later than Swift 5.6, that makes this possible.
First, consider the following utilities:
protocol EquatablePair {
func perform() -> Bool
}
protocol MaybeEquatablePair {
func maybePerform() -> Bool?
}
struct Pair<T> {
var lhs: T
var rhs: T
}
extension Pair: MaybeEquatablePair {
func maybePerform() -> Bool? {
(self as? EquatablePair)?.perform()
}
}
extension Pair: EquatablePair where T: Equatable {
func perform() -> Bool {
lhs == rhs
}
}
Here, we have a conditional conformance of Pair to EquatablePair. This allows us to use self as? EquatablePair to dynamically determine if T is Equatable. The MaybeEquatablePair conformance uses this trick to produce a boolean result if T is Equatable and nil otherwise.
The next part is to get Pair<T> for some concrete type T. We really need to get Pair<T> and not Pair<Any>. This is what helps me distinguish this subtle difference: Any is nothing but a struct of two fields, one being the pointer to the wrapped value’s type and the other the pointer to the actual value. The reality is slightly more complicated but this should give you some intuition. In this way, 1 as Int gives you a plain integer, where as (1 as Int) as Ayn gives you a special struct, hence Pair<Int> is very different from Pair<Any>.
So how can we dynamically fetch some Any’s wrapped value’s type and use that to get a desired Pair<T>? Here comes _openExisential:
func genericEqual(_ lhs: Any, _ rhs: Any) -> Bool {
func openLHS<LHS>(_ lhs: LHS) -> Bool {
if let rhs = rhs as? LHS {
return Pair(lhs: lhs, rhs: rhs).maybePerform() ?? false
} else {
return false
}
}
return _openExistential(lhs, do: openLHS)
}
_openExisential takes a wrapped value and use it to call some generic function. This magic function will dynamically fetch the type for its first argument and use that to call the generic function dynamically. This is not possible using plain Swift, in which calls to generic functions must have types resolved statically.
_openExisential can do more than Any. You might have heard the term existential types. This function can, well, open existential containers. It is a very complicated topic. See the Swift Evolution proposal Implicitly Opened Exisentials if you are interested.
My code is simplified from Foundation’s implementation for AttributedString. They seem to have a set of utilities to call Equatable, Encodable, Decodable implementation for Anys. Check out AttributedString.swift and AttributedStringAttribute.swift for more. Start with struct CheckEqualityIfEquatable.