Swift Extension and 'Element' explicit initialization - swift

I wonder if is there any other way to explicitly initialize an Element object in a Swift extension ?
For example I would like to do this but non-nominal type 'Element' does not support explicit initialization
extension Array where Element: Numeric {
func findDuplicate() -> Int {
guard self.count > 0 else { return -1 }
let sum = self.reduce(0, +)
let expectedSum = Element((self.count - 1) * self.count / 2)
return sum - expectedSum
}
}
Of course if I remove the forced Element casting in the expectedSum assignment and let the compiler use an Int I obtain an error comparing sum (Element) and expectedSum (Int)
I can easily have my extension working with where Element == Int but of course this is no more generic in this way.
Any hints?

Conversion of an integer to a Numeric type is done with init?(exactly:). Taking Leo's suggestions into account:
extension Array where Element: Numeric {
func findDuplicate() -> Element? {
guard !isEmpty else { return nil }
let sum = self.reduce(0, +)
guard let expectedSum = Element(exactly: (count - 1) * count / 2) else { return nil }
return sum - expectedSum
}
}
On the other hand, this seems to be a programming task that
is specifically about integers, and then it might make more sense
to restrict the element type to BinaryInteger (and use Int
for the intermediate calculations to avoid overflow):
extension Array where Element: BinaryInteger {
func findDuplicate() -> Element? {
guard !isEmpty else { return nil }
let sum = Int(reduce(0, +))
let expectedSum = (count - 1) * count / 2
return Element(sum - expectedSum)
}
}
or even Element == Int.

Related

How to get next case of enum(i.e. write a circulating method) in Swift 4.2

Swift 4.2 introduces a new CaseIterable protocol that automatically generates an array property of all cases in an enum.
Now I want to implement a default method for Enum inherits from CaseIterable that can return the next case of a giving case. If this case is the last case, return the first case. Like a circle.
If I write this for specific Enum, it works correctly:
enum Direction: CaseIterable {
case east, south, west, north
func next() -> Direction {
let all = type(of: self).allCases // 1
if self == all.last! {
return all.first!
} else {
let index = all.firstIndex(of: self)!
return all[index + 1]
}
}
}
print(Direction.east.next()) // south
print(Direction.north.next()) // east
But I want to implement this function to many Enum. Copying and pasting code repeatedly are not good (Not to mention this code is totally the same for every Enum).
So I tried this. But something went wrong.
(I suggest you copy following code to playground that you can understand this problem more quickly):
extension CaseIterable {
func next() -> Self {
let all = type(of: self).allCases // 1
if self == all.last { // 2
return all.first!
} else {
let index = all.firstIndex { (ele) -> Bool in
self == ele // 3
}
return all[index + 1]
}
}
}
Three points:
all's type is Self.AllCases, which is a Collection type. But in the method above, it's [Direction].
There's an error at line 2 says Value of type 'Self.AllCases' has no member 'last'
(Even I avoid to use last, the error at line 3 can't be avoided.)
At line 3, the error is Binary operator '==' cannot be applied to two 'Self' operands
And even I use generic constraints, it's the same.
func next<T: CaseIterable>(element: T) -> T {...}
Any solutions? :)
Some problems with your approach are:
The Collection protocol does not define a last property.
In order to compare the elements with == they have to be Equatable.
Collection indices are not necessarily integers, they must be incremented
with index(after:).
This seems to be a working solution (tested with Xcode 10.0 beta 2):
extension CaseIterable where Self: Equatable {
func next() -> Self {
let all = Self.allCases
let idx = all.firstIndex(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
Example:
enum Direction: CaseIterable {
case east, south, west, north
}
print(Direction.east.next()) // south
print(Direction.north.next()) // east
Remarks:
Only enumerations without associated values are CaseIterable, and
those are also Equatable (but the compiler does not figure out that
by itself). Therefore Self: Equatable is not a
real restriction.
Self.allCases can be used in Swift 4.2 to access the type property
from an instance method.
The forced unwrapping is safe because we know that the value is
an element of allCases.
Your enum Direction: CaseIterable compiles because the concrete
enum Direction type is Equatable, and its Direction.allCases is an Array – which has integer indices and a last property.
If someone is interested into both previous and next cases, here's an upgrade of the previous answer:
extension CaseIterable where Self: Equatable, AllCases: BidirectionalCollection {
func previous() -> Self {
let all = Self.allCases
let idx = all.index(of: self)!
let previous = all.index(before: idx)
return all[previous < all.startIndex ? all.index(before: all.endIndex) : previous]
}
func next() -> Self {
let all = Self.allCases
let idx = all.index(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
Actually you don't need BidirectionalCollection conformance to implement previous case as well.
extension CaseIterable where Self: Equatable {
func previous() -> Self {
let all = Self.allCases
var idx = all.firstIndex(of: self)!
if idx == all.startIndex {
let lastIndex = all.index(all.endIndex, offsetBy: -1)
return all[lastIndex]
} else {
all.formIndex(&idx, offsetBy: -1)
return all[idx]
}
}
func next() -> Self {
let all = Self.allCases
let idx = all.firstIndex(of: self)!
let next = all.index(after: idx)
return all[next == all.endIndex ? all.startIndex : next]
}
}
You can also make a more generic cyclic offset function:
extension CaseIterable where Self: Equatable {
func advanced(by n: Int) -> Self {
let all = Array(Self.allCases)
let idx = (all.firstIndex(of: self)! + n) % all.count
print(idx)
if idx >= 0 {
return all[idx]
} else {
return all[all.count + idx]
}
}
}
2022
We can create extension:
extension Collection {
subscript (infinityIdx idx: Index) -> Element where Index == Int {
return self[ idx % self.count ]
}
}
lets try this ext in action:
enum SomeEnum: CaseIterable {
case v1, v2, v3, v4
}
for i in 0...15 {
print(SomeEnum.allCases[infinityIdx: i] )
}
result:
v1
v2
v3
v4
v1
v2
v3
v4
v1
v2
v3

Stridable Protocol

I am trying to convert the following Swift 2.3 code:
//Example usage:
//(0 ..< 778).binarySearch { $0 < 145 } // 145
extension CollectionType where Index: RandomAccessIndexType {
/// Finds such index N that predicate is true for all elements up to
/// but not including the index N, and is false for all elements
/// starting with index N.
/// Behavior is undefined if there is no such N.
func binarySearch(predicate: Generator.Element -> Bool)
-> Index {
var low = startIndex
var high = endIndex
while low != high {
let mid = low.advancedBy(low.distanceTo(high) / 2)
if predicate(self[mid]) {
low = mid.advancedBy(1)
} else {
high = mid
}
}
return low
}
}
into Swift 3 as follows:
//Example usage:
//(0 ..< 778).binarySearch { $0 < 145 } // 145
extension Collection where Index: Strideable {
/// Finds such index N that predicate is true for all elements up to
/// but not including the index N, and is false for all elements
/// starting with index N.
/// Behavior is undefined if there is no such N.
func binarySearch(predicate: (Generator.Element) -> Bool)
-> Index {
var low = startIndex
var high = endIndex
while low != high {
let mid = low.advanced(by: low.distance(to: high) / 2)
if predicate(self[mid]) {
low = mid.advanced(to: 1)
} else {
high = mid
}
}
return low
}
}
The error
Binary operator '/' cannot be applied to operands of type 'self.Index.Stride' and 'Int'
is thrown at let mid = low.advanced(by: low.distance(to: high) / 2)
Any help on how to fix it?
In Swift 3, "Collections move their index", compare
A New Model for Collections and Indices on Swift evolution. In particular, you don't call advancedBy() on an index,
but an index() method on the collection to advance indices.
So your method would be implemented in Swift 3 as
extension RandomAccessCollection {
func binarySearch(predicate: (Iterator.Element) -> Bool) -> Index {
var low = startIndex
var high = endIndex
while low != high {
let mid = index(low, offsetBy: distance(from: low, to: high)/2)
if predicate(self[mid]) {
low = index(after: mid)
} else {
high = mid
}
}
return low
}
}
The same method would also compile (and work) as an extension of the
more general Collection type, but – as Vadim Yelagin correctly remarked,
is very inefficient if the index/offset calculations cannot be done in
constant time.

Getting a random element in array by a generic function

func ramElment<X, T: CollectionType >(list: T) -> X {
let len = UInt32(list.count)
let element = arc4random_uniform(len)
return list[element]
}
it pops up:
error: cannot invoke initializer for type UInt32 with an argument list of type '(T.Index.Distance)'
let len = UInt32(list.count)
I have checked the T.Index.Distance is Int type. but why can't i change the type to UInt32?
thanks!
The Index of a CollectionType is
a ForwardIndexType:
public protocol ForwardIndexType : _Incrementable {
// ...
typealias Distance : _SignedIntegerType = Int
// ...
}
This means that the associated type Distance must conform to _SignedIntegerType, and (by default) is Int unless declared (or inferred)
otherwise.
Example: The following is a valid type conforming to ForwardIndexType,
with Distance == Int16:
struct MyIndex : ForwardIndexType {
var value : Int16
func advancedBy(n: Int16) -> MyIndex {
return MyIndex(value: value + n)
}
func distanceTo(end: MyIndex) -> Int16 {
return end.value - value
}
func successor() -> MyIndex {
return MyIndex(value: value + 1)
}
}
func ==(lhs : MyIndex, rhs : MyIndex) -> Bool {
return lhs.value == rhs.value
}
And here is a (for demonstration purposes, otherwise pretty useless)
type conforming to CollectionType with Index == MyIndex,
Index.Distance == Int16:
struct MyCollectionType : CollectionType {
var startIndex : MyIndex { return MyIndex(value: 0) }
var endIndex : MyIndex { return MyIndex(value: 3) }
subscript(position : MyIndex) -> String {
return "I am element #\(position.value)"
}
}
Example:
let coll = MyCollectionType()
for elem in coll {
print(elem)
}
/*
I am element #0
I am element #1
I am element #2
*/
But we can also define a forward index type without declaring
any Distance type, and using the default protocol implementations
for advancedBy() and distanceTo():
struct MyOtherIndex : ForwardIndexType {
var value : Int16
func successor() -> MyOtherIndex {
return MyOtherIndex(value: value + 1)
}
}
func ==(lhs : MyOtherIndex, rhs : MyOtherIndex) -> Bool {
return lhs.value == rhs.value
}
Now MyOtherIndex.Distance == Int because that is the default type
as defined in ForwardIndexType.
So how does this apply to your function?
You cannot assume that
Index.Distance is Int for an arbitrary collection.
You can restrict the function to collection types with
Index.Distance == Int:
func randomElement<T: CollectionType where T.Index.Distance == Int>(list: T)
But you can also utilize that _SignedIntegerType can be converted to and from IntMax:
func randomElement<T: CollectionType>(list: T) -> T.Generator.Element {
let len = UInt32(list.count.toIntMax())
let element = IntMax(arc4random_uniform(len))
return list[list.startIndex.advancedBy(T.Index.Distance(element))]
}
Note also that the return type is determined as T.Generator.Element,
and cannot be an arbitrary generic type X.
This function works with arbitrary collections, for example Array, ArraySlice, or String.CharacterView:
let array = [1, 1, 2, 3, 5, 8, 13]
let elem1 = randomElement([1, 2, 3])
let slice = array[2 ... 3]
let elem2 = randomElement(slice)
let randomChar = randomElement("abc".characters)
but also with the above custom collection type:
let mc = MyCollectionType()
let r = randomElement(mc)
In the title of your question you talk about Array. But in your code you are declaring the input param as a CollectionType.
If you really want to receive a Generic Array param then this is the code
func randomElement<T>(list: [T]) -> T {
let len = UInt32(list.count)
let random = Int(arc4random_uniform(len))
return list[random]
}
This is the simplest example what you want.
extension CollectionType where Index.Distance == Int {
func randomElement() -> Self.Generator.Element {
let randomIndex = Int(arc4random_uniform(UInt32(count)))
return self[startIndex.advancedBy(randomIndex)]
}
}

Is it possible to create a "Positive Number" type in Swift?

Sorry if this is a stupid question but I'm wondering if there's a way in Swift to create a type that exclusively holds numbers that are strictly greater than zero and where the "positiveness" of the values is enforced at compile time.
For example, can I create somehow write code like
func divide(x: PositiveNumber, y: PositiveNumber){
return x / y
}
such that
divide(1, 3)
works but
divide(1, 0)
won't compile?
The closest thing I could come up with was a struct with only one fallible initializer such that the type has either a positive value or is nil:
struct PositiveNumber {
let value: Float
init?(value: Float){
if value > 0 {
self.value = value
} else {
return nil
}
}
}
func / (left: PositiveNumber, right: PositiveNumber) -> Float {
return left.value / right.value
}
func divide(x: PositiveNumber?, y: PositiveNumber?) -> Float? {
if let x = x, y = y {
return x / y
}
return nil
}
let x1 = PositiveNumber(value: 1)
let y1 = PositiveNumber(value: 3)
let x2 = PositiveNumber(value: -1)
let y2 = PositiveNumber(value: 0)
divide(x1, y: y1)! // .333
divide(x2, y: y2)! // runtime error
That's not terrible but we still have to deal with a lot of optional handling/unwrapping. I'm asking this question because I have many places in my code where I need to check that a value is not zero and I'm curious if there's a way to remove that code and let the compiler handle it. The struct-based solution requires pretty much the same amount of code.
Number Type build on Float
This gist is contains a Struct that conforms to pretty much everything Float conforms too. It is just a vanilla copy of Float, change it to your liking.
Have you considered a custom operator?
infix operator /+ { associativity left precedence 150 }
func /+(lhs:Float,rhs:Float) -> Float? {
guard rhs > 0 else {
return nil
}
return lhs / rhs
}
let test = 2 /+ -1 // nil
let test2 = 2 /+ 1 // 2
let test3 = 2 /+ 1 + 2 // warning
It doesn't really matter if you let it return an optional, or an enum value, or different protocols. You will have to handle the return. But this way you get compiler warnings.
Limited Number Type with just an operator to handle divisions:
You could change math altogether and create a PositiveNumber Type that returns NaN when dividing by a value less than Zero.
public struct PositiveFloat {
public var value: Float
/// Create an instance initialized to zero.
public init() {
self.value = 0
}
/// Create an instance initialized to `value`.
public init(_ value: Float) {
self.value = value
}
public init(_ value: PositiveFloat) {
self.value = value.value
}
}
extension Float {
public var positive : PositiveFloat {
return PositiveFloat(self)
}
}
public func /(lhs:Float,rhs:PositiveFloat) -> Float {
if 0 > rhs.value {
return lhs / rhs.value
} else {
return Float.NaN
}
}
public func /(lhs:PositiveFloat,rhs:PositiveFloat) -> Float {
if 0 > rhs.value {
return lhs.value / rhs.value
} else {
return Float.NaN
}
}
let testNormal : Float = 10
let testFloat : Float = -5
let test = testFloat / testNormal.positive
if test.isNaN {
// do stuff
}

Map OptionSetType to Array

Given the following:
struct Weekdays: OptionSetType {
let rawValue: Int
init(rawValue: Int) { self.rawValue = rawValue }
static let Monday = Weekdays(rawValue: 1)
static let Tuesday = Weekdays(rawValue: 2)
static let Wednesday = Weekdays(rawValue: 4)
static let Thursday = Weekdays(rawValue: 8)
static let allOptions: [Weekdays] = [.Monday, .Tuesday, .Wednesday, .Thursday]
}
I can convert an array of Ints into a Weekdays object by doing this:
let arr = [1, 4]
let weekdays = arr.reduce(Weekdays()) { $0.union(Weekdays(rawValue: $1)) }
My question is, how do I take a Weekdays object and convert it into an array of Ints?
(Not necessarily better, but a different way to look at it and slightly
more general).
OptionSetType inherits from RawRepresentable and therefore can be
converted from and to the associated raw type, which in your case is
Int.
So the "missing link" is a conversion between the raw value (e.g. 5)
and an integer array of the bitwise components (e.g. [1, 4]).
This can be done with an Int extension method:
extension Int {
init(bitComponents : [Int]) {
self = bitComponents.reduce(0, combine: (+))
}
func bitComponents() -> [Int] {
return (0 ..< 8*sizeof(Int)).map( { 1 << $0 }).filter( { self & $0 != 0 } )
}
}
Then your conversion from an array to a Weekdays object becomes
let arr : [Int] = [1, 4]
let weekdays = Weekdays(rawValue: Int(bitComponents: arr))
print(weekdays)
// app.Weekdays(rawValue: 5)
and the reverse conversion
let array = weekdays.rawValue.bitComponents()
print(array)
// [1, 4]
Advantages:
The explicit definition of allOptions: is not needed.
It can be applied to other option set types (which have Int
as a raw value).
One could also try to define the conversions as a protocol extension,
e.g. of IntegerType, so that the same works with other integer raw types as well. However, this seems to be a bit complicated/ugly
because the left shift operator << is not part of the
IntegerType (or any) protocol.
Update for Swift 3:
extension Int {
init(bitComponents : [Int]) {
self = bitComponents.reduce(0, +)
}
func bitComponents() -> [Int] {
return (0 ..< 8*MemoryLayout<Int>.size).map( { 1 << $0 }).filter( { self & $0 != 0 } )
}
}
Not exactly answering the question, but might be useful to others. Based on Martin's answer I extract back the component objects:
extension FixedWidthInteger {
init(bitComponents : [Self]) {
self = bitComponents.reduce(0, +)
}
var bitComponents : [Self] {
(0 ..< Self.bitWidth).map { 1 << $0 } .filter { self & $0 != 0 }
}
}
extension OptionSet where RawValue: FixedWidthInteger, Self == Self.Element {
var components : [Self] { rawValue.bitComponents.map(Self.init) }
}
As I was writing the question, I figured it out:
let array = Weekdays.allOptions.filter { weekdays.contains($0) }.map { $0.rawValue }
Is there a better way?
You can improve the context of your extension by defining it conditionally on OptionSet.
extension OptionSet where RawValue: UnsignedInteger {
var individualCases: [Self] {
return (0..<(8 * MemoryLayout<RawValue>.size))
.map { bitsToShift in RawValue(1 << bitsToShift) } // Get every possible single-bit flag
.filter { (powerOfTwo: RawValue) -> Bool in rawValue & powerOfTwo != 0 } // filter out only the cases the receiver contains
.map { Self(rawValue: $0) } // create the `OptionSet` (single bit) type
}
}
let weekdays = Weekdays(rawValue: 0b11111)
weekdays.individualCases.map { $0.rawValue } // [1, 2, 4, 8, 16]
A warning: On my 13" 2019 MacBookPro, I had to provide all of the explicit types above to keep the methods type checking under 1500ms in Swift 5.0.
Thanks to MartinR for the inspiration to loop of the memory layout size.
To complete the example, I've updated the weekday type to Swift 5 below, and explicitly used the UInt8 type to make the individualCases more efficient. With UInt, it would loop over the first map and filter 64 times each, with UInt8 it only loops 8 times.
struct Weekdays: OptionSet {
let rawValue: UInt8
static let Monday = Weekdays(rawValue: 1)
static let Tuesday = Weekdays(rawValue: 2)
static let Wednesday = Weekdays(rawValue: 4)
static let Thursday = Weekdays(rawValue: 8)
static let Friday = Weekdays(rawValue: 16)
}