Functions on generic arrays - swift

I would like to use more functional programming in Swift. Some of the functions I write could work well on Arrays of various types. I don't want to rewrite the same function with different types (or typealiases.) The pattern how the function would work is often the same, just with different types. So, I tried something like this:
// Add indeces to an array of any type. I.e., returns an array of tuples of the array index and the original element.
func addIndeces<T: AnyObject>(toArray: Array<T>) -> Array<(index: Int, value: T)> {
var arrIndex: [Int] = []
for index in 0...toArray.count {
arrIndex.append(index)
}
return Array(Zip2(arrIndex, toArray))
}
When I call this function
// Note: reminderList is of type [Reminder]
let indexedReminderList = addIndeces(reminderList) as! [(index: Int, reminder: Reminder)]
I get a runtime error: "fatal error: can't unsafeBitCast between types of different sizes"
What am I doing wrong?

The function you are writing already exists – kind of. enumerate "return a lazy SequenceType containing pairs (n, x), where n\ s are consecutive Int\ s starting at zero, and x\ s are the elements of base"
This means you can write your function as:
func addIndices<T>(toArray: [T]) -> [(index: Int, reminder: T)] {
// if you want to label the tuple elements index: and reminder:,
// you still have to use map:
return map(enumerate(toArray)) {
(index: $0, reminder: $1)
}
}
Note, you don’t need to write T: AnyObject unless you specifically want to prevent this function from accepting anything other than arrays of classes (as that's what AnyObject is - the protocol that only classes, not structs or enums, conform to).
Note, enumerate only works for integer-indexed collections. To make it more general, you could write zip(indices(someCollection),someCollection)). indices returns a range of all the indices of any collection, so is equivalent to someCollection.startIndex..<someCollection.endIndex.

You want to cast the tuple Array of type [(index: Int, value: T)] where T is of type Reminder to a tuple Array of type [(index: Int, reminder: Reminder)]. So you can see that the tuples have different element names (value and reminder) where both have different byte sizes - therefore the error.
So you should take the same element names for both tuples.
If you want to change the element names:
let newTupleArray = oldTupleArray.map{ (newElementName0: $0.0, newElementName1: $0.1) }

The range 0...toArray.count consist all elements form 0 to the count of toArray, including the count value, and in your case arrIndex will always have one more element then toArray. Thats what is causing different size error. To fix it replace your range with this one 0..<toArray.count

Related

What does Array and ... does here?

I have this line here, I can not understand the purpose, and the sytacs.
instances = Array(Array(instance.enumerated())[prefixItems.count...])
What does ...
What does [prefixItems.count...] when creating an Array?
How instances can be assigned to a type like: [(Int, Any)].
this is the whole statement, it is syntactically valid:
let instances: [(Int, Any)]
if let prefixItems = schema["prefixItems"]?.array {
guard instance.count > prefixItems.count else {
return AnySequence(EmptyCollection())
}
instances = Array(Array(instance.enumerated())[prefixItems.count...])
} else {
instances = Array(instance.enumerated())
}
but for some reason I need convert Any to DataToValidate, like:
let instances: [(Int, DataToValidate)]
and then I got error:
Cannot assign value of type 'Array<EnumeratedSequence<(JSONArray)>.Element>' (aka 'Array<(offset: Int, element: JSONValue)>') to type '[(Int, DataToValidate)]'
The x... is a one-sided range from x to "as far as possible", i.e., to the end of the array in case of subscripting, as done here.
Array(instance.enumerated()) initializes an array from the enumerated sequence instance, i.e., [(Int, Any)]. The subscript [prefixItems.count...] takes the elements from that array starting from the index prefixItems.count and continuing to the end. The outer Array initializes an array of that sequence.
The types of everything involved above (in practice some will have more specific actual types, but they conform to these):
instance – some Sequence, but we can consider it [Any]
instance.enumerated() – Sequence<(Int, Any)>
Array(instance.enumerated()) – [(Int, Any)]
Array(instance.enumerated())[prefixItems.count...] – Sequence<(Int, Any>)>
Array(Array(instance.enumerated())[prefixItems.count...]) – [(Int, Any)]
P. S. As pointed out in comments, note that the intermediate array and subscripting is unnecessary, and the same outcome can be achieved with Array(instance.enumerated().dropFirst(prefixItems.count)). This also makes the guard unnecessary.

In Swift what does Element mean when writing an extension on Array?

What does Element mean when writing an extension on Array?
like in this example:
extension Array {
func reduce<T>(_ initial: T, combine: (T, Element) -> T) -> T {
var result = initial
for x in self {
result = combine(result, x)
}
return result
}
}
The combine parameter is a function which takes a parameter of type T and Element. The Element is the actual Element of/in the array.
For example, this is an array of Int elements:
let arr = [1,2,5,77]
In reduce, initial is of type T. This is the staring value for the mapping you are about to perform.
In combine, T is like your starting value for each subsequent step of combing the next Element to produce another value of type T which will be used as the next T in combine, and so and so forth until the entire array has been processed.
If you were using a default use of reduce such as:
arr.reduce(0, +)
You can see that in this case, T and Element would both be of the same type, Int.
However, I could have a custom object that the array is of, and my combine is defining how to get the running total. If you had something like this:
struct Thing {
var val1: String
var val2: Int
}
let thingArray = //...define some Things in an array
You could use reduce and define your own combine function to return the sum of all the val2 values. In this case, T would be an Int, and Element would be Thing.

Compare two objects in Swift without casting to a specific type

I'm trying to compare two objects whose type is known at run time but not at compile time. So far I have the following function which seems to work as written:
/// Compares two objects of the given type.
/// Returns -1 if a is "less than" b, 1 if a is "greater than" b, 0 if they are equal, and nil if no comparison could be made.
func compare<T: Comparable>(type: T.Type, a: Any?, b: Any?) -> Int? {
guard let at = a as? T, let bt = b as? T else { return nil }
return at < bt ? -1 : at > bt ? 1 : 0
}
The problem is, the type is not necessarily known to comply with the Comparable protocol at compile time; I really need to be able to pass in any type (Any.Type), not just Comparable ones. I'd then like the function to return nil if the passed-in type does not conform to Comparable. How can I do this?
Edit (30/08/2018): Some more context. I'm using this function to sort various arrays of strings, integers, and other Comparable types. However, because these arrays are retrieved via reflection the element types are not known at compile time. I know that they will always be Comparable but the compiler doesn't. To resolve this, I'm passing in the type as a separate parameter as shown. However, because I'd like to keep the logic as general as possible I'm performing this sort function inside a conditional statement which chooses the necessary type from an array. The type of this array must be [Any.Type] to hold the required types, even though all its contents conform to Comparable (String.Type, Date.Type, etc.).

Swift generic constraints based on operator

Suppose I want to add up all the values of an entry of an array. Not only integers, but also double values or some type I created myself which implements the + operator. So my question is: Is it possible to create such a function with a constraint that is based on the fact if the type implements the operator? Such as or something like that (obviously THIS isn't working).
Thanks in advance
There are several ways you can approach the problem.
IntegerArithmeticType
While I know of no explicit way to say "Hey Swift, I want to only allow type T where T has this operator", all types we commonly think of as capable of being added, subtracted, multiplied, and divided automatically conform to IntegerArithmeticType, which can be used as a generic constraint for any generic function or type.
For example:
func addAll<T: IntegerArithmeticType>(array: [T]) -> T {
var count = array[0]
for (index, value) in array.enumerate() {
if index != 0 {
count += value
}
}
return count
}
Notice in this quick mock-up version I initialized count with the first value of the array and then avoiding double-counting by checking the index against 0 inside the for loop. I can't initialize count with 0 because 0 is an Int while I want count to be of type T.
You mentioned having your own types work with this too. One option is to have your custom type conform to IntegerArithmeticType, although it requires a lot more than just the + operator. For details on IntegerArithmeticType, see SwiftDoc.
Custom Protocol
If conforming to IntegerArithmeticType imposes some sort of limitation on you, you can create a custom protocol with the + function and whatever other requirements you would like. After all, operators are really just functions. Note that you can add conformance to already existing types with extensions. For example:
protocol Addable {
func +(left: Self, right: Self) -> Self
// Other requirements...
}
extension Int: Addable {}
extension Double: Addable {}

Tuple and Function Argument in Swift

In Swift, how is tuple related to function argument?
In the following two examples the function returns the same type even though one takes a tuple while the other takes two arguments. From the caller standpoint (without peeking at the code), there is no difference whether the function takes a tuple or regular arguments.
Is function argument related to tuple in some ways?
e.g.
func testFunctionUsingTuple()->(Int, String)->Void {
func t(x:(Int, String)) {
print("\(x.0) \(x.1)")
}
return t
}
func testFuncUsingArgs()->(Int, String)->Void {
func t(x:Int, y:String) {
print("\(x) \(y)")
}
return t
}
do {
var t = testFunctionUsingTuple()
t(1, "test")
}
do {
var t = testFuncUsingArgs()
t(1, "test")
}
There is also inconsistencies in behavior when declaring tuple in function argument in a regular function (rather than a returned function):
func funcUsingTuple(x:(Int, String)) {
print("\(x.0) \(x.1)")
}
func funcUsingArgs(x:Int, _ y:String) {
print("\(x) \(y)")
}
// No longer works, need to call funcUsingTuple((1, "test")) instead
funcUsingTuple(1, "test")
funcUsingArgs(1, "test3")
UPDATED:
Chris Lattner's clarification on tuple:
"x.0” where x is a scalar value produces that scalar value, due to odd
behavior involving excessive implicit conversions between scalars and
tuples. This is a bug to be fixed.
In "let x = (y)”, x and y have the same type, because (x) is the
syntax for a parenthesis (i.e., grouping) operator, not a tuple
formation operator. There is no such thing as a single-element
unlabeled tuple value.
In "(foo: 42)” - which is most commonly seen in argument lists -
you’re producing a single element tuple with a label for the element.
The compiler is currently trying hard to eliminate them and demote
them to scalars, but does so inconsistently (which is also a bug).
That said, single-element labeled tuples are a thing.
Every function takes exactly one tuple containing the function's arguments. This includes functions with no arguments which take () - the empty tuple - as its one argument.
Here is how the Swift compiler translates various paren forms into internal representations:
() -> Void
(x) -> x
(x, ...) -> [Tuple x ...]
and, if there was a tuple? function, it would return true on: Void, X, [Tuple x ...].
And here is your proof:
let t0 : () = ()
t0.0 // error
let t1 : (Int) = (100)
t1.0 -> 100
t1.1 // error
let t2 : (Int, Int) = (100, 200)
t2.0 -> 100
t2.1 -> 200
t2.2 // error
[Boldly stated w/o a Swift interpreter accessible at the moment.]
From AirSpeedVelocity
But wait, you ask, what if I pass something other than a tuple in?
Well, I answer (in a deeply philosophical tone), what really is a
variable if not a tuple of one element? Every variable in Swift is a
1-tuple. In fact, every non-tuple variable has a .0 property that is
the value of that variable.4 Open up a playground and try it. So if
you pass in a non-tuple variable into TupleCollectionView, it’s legit
for it to act like a collection of one. If you’re unconvinced, read
that justification again in the voice of someone who sounds really
confident.
Remember the 'philosophical tone' as we've reached the 'I say potato; your say potato' phase.
A function in Swift takes a tuple as parameter, which can contain zero or more values. A parameterless function takes a tuple with no value, a function with one parameter takes a tuple with 1 value, etc.
You can invoke a function by passing parameters individually, or by grouping them into an immutable tuple. For example, all these invocations are equivalent:
do {
let t1 = testFunctionUsingTuple()
let t2 = testFuncUsingArgs()
let params = (1, "tuple test")
t1(params)
t1(2, "test")
t2(params)
t2(3, "test")
}