Swift Array.map closure issue - arrays

I want to improve on a closure I wrote using Swift's Array.map function
I'm basically taking an Array and remapping all of its elements using a closure.
// Here's the array:
var numbersArray = [1, 2, 3, 4, 5]
// Here's the closure - it takes whatever number is passed into it and
// multiplies it by 2.0
var multiplier = { (currentNum: Int) -> Double in
let result = Double(currentNum) * 2.0
return result
}
// And here's how I'm calling it:
var newArray = numbersArray.map(multiplier)
And this works perfectly.
But what if I want to multiply everything by 2.1? or 3.5? or any value? In other words, what if I want to make the amount I multiply by also be a variable? And have it be passed into the closure as a second argument?
I tried adding it to the argument list like this:
var multiplier = { (currentNum: Int, factor: Double) -> Double in
let result = Double(currentNum) * factor
return result
}
and then changing my call to this:
var newArray = numbersArray.map(multiplier, 3.5)
but I'm getting all sorts of errors (and I tried all sorts of variations on this of course.)
What am I doing wrong?

Edit: Note: This language feature was removed in Swift 2.
A swift-er way than connor's answer (but along the same lines), is to use a curried function. From The Swift Programming Language->Language Reference->Declarations->Curried Functions and Methods:
A function declared this way is understood as a function whose return
type is another function.
So you can simplify this:
func multiplier(factor: Double) -> (Int)->Double
{
return { (currentNum: Int) -> Double in
let result = Double(currentNum) * factor
return result
}
}
to this:
func multiplier(factor: Double)(currentNum: Int) -> Double {
return Double(currentNum) * factor
}
and use it exactly the same way:
let numbersArray = [1, 2, 3, 4, 5]
let multipliedArray = numbersArray.map(multiplier(3.5))

You can use a higher order function to produce a custom function that you can then use with the array's map function. Like this:
var numbersArray = [1, 2, 3, 4, 5]
func multiplier(factor: Double) -> (Int)->Double
{
return { (currentNum: Int) -> Double in
let result = Double(currentNum) * factor
return result
}
}
var newArray = numbersArray.map(multiplier(2.5))

Related

Programatically create storage arrays for DSPSplitComplex complex numbers

I am using Apple's Accelerate framework with swift. I am working with DSPSplitComplex numbers to work with complex vectors.
I would like to create a filter bank (An array of filters). To do this, I iterate through a loop, and add the result to my array using the following code:
func makeSine(freq:Float, N:Int) -> DSPSplitComplex {
var sreal:[Float] = Array(repeating: 0, count: N)
var simag:[Float] = Array(repeating: 0, count: N)
var compSine = DSPSplitComplex(realp: UnsafeMutablePointer(mutating:sreal), imagp: UnsafeMutablePointer(mutating:simag))
for i in 0..<t.count{
var x = 2 * Float.pi * freq * t[i]
sreal[i] = cos(x)
simag[i] = sin(x)
}
return compSine
}
the function above makes a complex sine wave. I call the function with:
var s = makeSine(freq:400.0, N:2048)
My issue is using DSPSplitComplex I am creating pointers to the arrays initialised in the function. I cannot inspect the variable s directly in the debug area in Xcode, however I achieve this using the following code:
var inspect:[Float]=[]
for i in 0..<t.count {
inspect.append(s.realp[I])
}
t.count being the length of the filter. Comparing the values of this array with the values printed out whilst inside the makeSine function, they are both very different. Because this is just a pointer, I believe it is not passing the actual values and these arrays are being deallocated.
My problem is that I am looking at iterating through the makeSine (and other functions) a few hundred times, resulting in hundreds of realp and imagp arrays. How do I handle these programatically?
Okay, I actually found a way around this earlier than I thought and posting to help others.
At the top of my class I initialise the separate arrays for the real and imaginary parts:
var realSines:[[Float]]=[]
var imagSines:[[Float]]=[]
then the rewritten makeSine function is:
func makeSine(freq:Float, N:Int, iteration:Int) -> DSPSplitComplex {
var sreal:[Float] = Array(repeating: 0, count: N)
var simag:[Float] = Array(repeating: 0, count: N)
var compSine = DSPSplitComplex(realp: UnsafeMutablePointer(mutating:sreal), imagp: UnsafeMutablePointer(mutating:simag))
for i in 0..<t.count{
var x = 2 * Float.pi * freq * t[i]
sreal[i] = cos(x)
simag[i] = sin(x)
}
realSines.append(sreal)
imagSines.append(simag)
}
then whenever I want to use a DSPSplitComplex I declare it with:
var tempSineReal = realSines[iteration]
var tempSineImag = imagSines[iteration]
var tempSine = DSPSplitComplex(realp: UnsafeMutablePointer(mutating:tempSineReal), imagp: UnsafeMutablePointer(mutating: tempSineImag))

N-Dimensional array swift

Is there any way to have an n dimensional array in swift? I would like to be able to make a function that creates an array with n dimensions but I cannot figure out how.
Basically something like this:
func ndarray <T> (dimensions: Int...) -> [[T]] { // What do I tell it I return?
var out
for d in dimensions {
out = Array<T>(repeating: out, count: d)
}
return out
}
The above code does not work for obvios reasons but, I think it points out the main problems I am having:
How do I define a return type
How do I actually create the array
Once created how do I traverse and populate the array
Here is the implementation of an N-Dimensional Array. It uses a normal array internally for storage and converts the multi-dimensional indices into a single index for the internal array.
struct NDimArray<T> {
let dimensions: [Int]
var data: [T]
init(dimensions: Int..., initialValue: T) {
self.dimensions = dimensions
data = Array(repeating: initialValue, count: dimensions.reduce(1, *))
}
init(dimensions: Int..., initUsing initializer: () -> T) {
self.dimensions = dimensions
data = (0 ..< dimensions.reduce(1, *)).map { _ in initializer() }
}
// Compute index into data from indices
private func computeIndex(_ indices: [Int]) -> Int {
guard indices.count == dimensions.count else { fatalError("Wrong number of indices: got \(indices.count), expected \(dimensions.count)") }
zip(dimensions, indices).forEach { dim, idx in
guard (0 ..< dim) ~= idx else { fatalError("Index out of range") }
}
var idx = indices
var dims = dimensions
var product = 1
var total = idx.removeLast()
while !idx.isEmpty {
product *= dims.removeLast()
total += (idx.removeLast() * product)
}
return total
}
subscript(_ indices: Int...) -> T {
get {
return data[computeIndex(indices)]
}
set {
data[computeIndex(indices)] = newValue
}
}
}
Example:
// Create a 3 x 4 x 5 array of String with initial value ""
var arr = NDimArray<String>(dimensions: 3, 4, 5, initialValue: "")
for x in 0 ..< 3 {
for y in 0 ..< 4 {
for z in 0 ..< 5 {
// Encode indices in the string
arr[x, y, z] = "(\(x),\(y),\(z))"
}
}
}
// Show internal storage of data
print(arr.data)
["(0,0,0)", "(0,0,1)", "(0,0,2)", "(0,0,3)", "(0,0,4)", "(0,1,0)", "(0,1,1)", "(0,1,2)", "(0,1,3)", "(0,1,4)", "(0,2,0)", "(0,2,1)", "(0,2,2)", "(0,2,3)", "(0,2,4)", "(0,3,0)", "(0,3,1)", "(0,3,2)", "(0,3,3)", "(0,3,4)", "(1,0,0)", "(1,0,1)", "(1,0,2)", "(1,0,3)", "(1,0,4)", "(1,1,0)", "(1,1,1)", "(1,1,2)", "(1,1,3)", "(1,1,4)", "(1,2,0)", "(1,2,1)", "(1,2,2)", "(1,2,3)", "(1,2,4)", "(1,3,0)", "(1,3,1)", "(1,3,2)", "(1,3,3)", "(1,3,4)", "(2,0,0)", "(2,0,1)", "(2,0,2)", "(2,0,3)", "(2,0,4)", "(2,1,0)", "(2,1,1)", "(2,1,2)", "(2,1,3)", "(2,1,4)", "(2,2,0)", "(2,2,1)", "(2,2,2)", "(2,2,3)", "(2,2,4)", "(2,3,0)", "(2,3,1)", "(2,3,2)", "(2,3,3)", "(2,3,4)"]
print(arr[2, 2, 2]) // "(2,2,2)"
print(arr[3, 0, 0]) // Fatal error: Index out of range
print(arr[0, 4, 0]) // Fatal error: Index out of range
print(arr[2]) // Fatal error: Wrong number of indices: got 1, expected 3
Initializing an Array with a Reference Type
As #DuncanC noted in the comments, you have to be careful when initializing an array with a value which is a reference type, because the array will be filled with references to the object and modifying the object at any index will modify all of them.
To solve this, I added a second initializer:
init(dimensions: Int..., initUsing initializer: () -> T)
which takes a closure () -> T which can be used to create a new object for each element of the array.
For example:
class Person {
var name = ""
}
// Pass a closure which creates a `Person` instance to fill the array
// with 25 person objects
let arr = NDimArray(dimensions: 5, 5, initUsing: { Person() })
arr[3, 3].name = "Fred"
arr[2, 2].name = "Wilma"
print(arr[3, 3].name, arr[2, 2].name)
Fred Wilma
Nope, it's not possible. Array dimensions is something that needs to be determined at compile time, while the argument you want to pass to the initializer will not be known until runtime. If you really want to achieve something like this, then you'll need to move the array indexing from compile time to runtime, e.g. by accessing the array via an array of indexes. Still you don't have compile validation, since the array length can at runtime to not match the dimensions of the array.
This problem is similar to the one that attempts to convert a tuple to an array.

Transforming RandomAccessSlice to RandomAccessCollection

When we try to retrieve a range of elements from an Array, we get back an ArraySlice:
let array = [1, 3, 5, 2]
let arraySlice = array[..<2] // elements up to index 1 == [1, 3]
We can transform it back to the Array type like so:
let arrayFromSlice = Array(arraySlice)
Let's say you want to create a method that returns the first 3 elements of any RandomAccessCollection:
func first3Elements<T: RandomAccessCollection>(_ c: T) -> T {
let slice = c.prefix(3)
// COMPILER ERROR: non-nominal type 'T'
// does not support explicit initialization
return T(slice)
}
Is it possible to perform this conversion?
Here my first attempt using type erasure but I guess there are better solutions.
func first3Elements<T>(_ c: AnyRandomAccessCollection<T>) -> AnyRandomAccessCollection<T> {
let slice = c.prefix(3)
return AnyRandomAccessCollection(slice)
}
let array = AnyRandomAccessCollection([1, 2, 3, 4])
let result = first3Elements(array)
for x in result {
print(x)
}

swift array storing data

I made a function that returns multiple values
let interestingNumbers = [ // String:Array<Int>
"Prime": [2, 3, 5, 7, 11, 23],
"Fibonacci": [1, 1, 2, 3, 5, 80],
"Square": [1, 4, 9, 16, 25],
]
func largestNum(objDictionary:[String:Array<Int>]) -> (Int,String) {
var largest = 0
var ki:String? = nil
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
ki=kind
}
}
}
return (largest , ki!)
}
print(largestNum(interestingNumbers)) //calling fuction and print
/*var ar2:[Int,String] = largestNum(interestingNumbers))
print(ar2)*/' this code have an error`
How can I store the returned values from the function in the array
Update:
If you want both values in a single array with ar[0] being the Int and ar[1] being the String, then you'll need to declare ar2 to be [Any] and unpack the tuple when initializing ar2:
let largest = largestNum(interestingNumbers)
var ar2:[Any] = [largest.0, largest.1]
print(ar2) // [80, "Fibonacci"]
If you just assign the return to ar2 and leave it as a tuple, you can access the values with ar2.0 and ar2.1:
var ar2 = largestNum(interestingNumbers)
print(ar2.0) // 80
print(ar2.1) // "Fibonacci"
Or if you change your largestNum to return a named tuple:
func largestNum(objDictionary:[String:Array<Int>]) -> (number: Int, kind: String) {
}
var ar2 = largestNum(interestingNumbers)
print(ar2.number) // 80
print(ar2.kind) // "Fibonacci"
Original Answer:
Declare your array ar2 to hold tuples pairs of Int and String, and then wrap your return value in [] to create an array:
var ar2:[(Int,String)] = [largestNum(interestingNumbers)]
print(ar2) // [(80, "Fibonacci")]
Because tuples are really meant for temporary values, it is better style to store values in an array using a struct:
Change your function to return an InterestingNumber:
struct InterestingNumber {
let kind: String
let number: Int
}
func largestNum(objDictionary:[String:Array<Int>]) -> InterestingNumber {
// contents omitted for brevity
return InterestingNumber(kind: ki!, number: largest)
}
let largest = largestNum(interestingNumbers)
// Define your array to hold `InterestingNumber`s:
var ar2:[InterestingNumber] = [largest]
print(ar2) // [InterestingNumber(kind: "Fibonacci", number: 80)]
If you meant for ar2 to just hold a single value, then simply do:
var ar2 = largestNum(interestingNumbers)
and Swift will infer the type (which is a tuple in your original code or an InterestingNumber when using the struct.
your code runs fine in xcode 7.3.1 playground
okay, now i get your question:
let z: (Int, String) = largestNum(interestingNumbers)
The part after the arrow in your function definition is the type (i think called tupel), you can use it for a variable.

Walk an UInt8 integer array in Swift; perform computation on subset of array

I've got an array of unsigned integers and I'd like to get a product of certain subsets.
For example, if my array was [2,2,1,5], I'd like the product of every two numbers (2 * 2 = 4 and 1 * 5 = 5).
So far, I've got:
var myArray:[UInt8] = [2,2,1,5]
var mySlice: Array<UInt8>
for (index,i) in enumerate(myArray) {
if (index % 2 == 1) {
mySlice = Array(myArray[(index - 1)...index])
println(mySlice.reduce(1,*))
mySlice.removeAll()
}
}
This seems like it would work (though ugly) but I get Execution was interrupted, reason: EXC_BAD_INSTRUCTION.
What's the best way to walk linearly down an array returning products (or computations) at certain intervals?
Thanks.
It looks like the problem is clearing out the slice while iterating the bigger array.
You should be able to work through this by adding the items to a separate array as you go, like this:
let myArray:[UInt8] = [2,2,1,5]
var result:[UInt8] = []
for (index,i) in enumerate(myArray) {
if (index % 2 == 1) {
let mySlice = Array(myArray[(index - 1)...index])
let tmp = mySlice.reduce(1,*)
result.append(tmp)
println(tmp)
}
}
println(result)
If you would like to put the results back into myArray, you can assign it after the loop.
Demo.
There are a few changes you can make that will make this much easier (and have much better performance) than your current attempt. First, use the global stride(from:to:interval:) function, which builds a sequence of indexes like the one you want -- no need to loop through all and skip the odd ones!
for i in stride(from: 0, to: myArray.count, by: 2) {
// ...
}
Second, you can use a slice's reduce method, so you don't have to convert a Slice back to an Array (doing so is unnecessary and inefficient):
let r = myArray[i ... i + 1].reduce(1, *)
So to bring it all together, your code could be:
var myArray: [UInt8] = [2, 2, 1, 5]
var result: [UInt8] = []
for i in stride(from: 0, to: myArray.count, by: 2) {
result.append( myArray[i...i + 1].reduce(1, *) )
}
// result is [4, 5]

Resources