In The Swift Programming Language, it says:
Functions can also take a variable number of arguments, collecting them into an array.
func sumOf(numbers: Int...) -> Int {
...
}
When I call such a function with a comma-separated list of numbers (`sumOf(1, 2, 3, 4), they are made available as an array inside the function.
Question: what if I already have an array of numbers that I want to pass to this function?
let numbers = [1, 2, 3, 4]
sumOf(numbers)
This fails with a compiler error, “Could not find an overload for '__conversion' that accepts the supplied arguments”. Is there a way to turn an existing array into a list of elements that I can pass to a variadic function?
Splatting is not in the language yet, as confirmed by the devs. Workaround for now is to use an overload or wait if you cannot add overloads.
Here's a work around that I found. I know it's not exactly what you want, but it seems to be working.
Step 1: Declare the function you'd like with an array instead of variadic arguments:
func sumOf(numbers: [Int]) -> Int {
var total = 0
for i in numbers {
total += i
}
return total
}
Step 2: Call this from within your variadic function:
func sumOf(numbers: Int...) -> Int {
return sumOf(numbers)
}
Step 3: Call Either Way:
var variadicSum = sumOf(1, 2, 3, 4, 5)
var arraySum = sumOf([1, 2, 3, 4, 5])
It seems strange, but it is working in my tests. Let me know if this causes unforeseen problems for anyone. Swift seems to be able to separate the difference between the two calls with the same function name.
Also, with this method if Apple updates the language as #manojid's answer suggests, you'll only need to update these functions. Otherwise, you'll have to go through and do a lot of renaming.
You can cast the function:
typealias Function = [Int] -> Int
let sumOfArray = unsafeBitCast(sumOf, Function.self)
sumOfArray([1, 2, 3])
You can use a helper function as such:
func sumOf (numbers : [Int]) -> Int { return numbers.reduce(0, combine: +) }
func sumOf (numbers : Int...) -> Int { return sumOf (numbers) }
I did this (Wrapper + Identity Mapping):
func addBarButtonItems(types: REWEBarButtonItemType...) {
addBarButtonItems(types: types.map { $0 })
}
func addBarButtonItems(types: [REWEBarButtonItemType]) {
// actual implementation
}
I know this response does not answer your exact question, but I feel its worth noting. I too was starting to play with Swift and immediately ran into a similar question. Manojlds answer is better for your question, I agree, but again, another workaround I came up with. I do happen to like Logan's better too.
In my case I just wanted to pass an array:
func sumOf(numbers: Array<Int>) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
var someNums = [8,7,2,9,12]
sumOf(someNums)
sumOf([10, 15, 20])
Just wanted to share, in case anyone else was thinking like me. Most of the time I would prefer pass the array like this, but I don't think the "Swiftly" yet. :)
Swift 5
This is an approach with #dynamicCallable feature that allows to avoid overloading or unsafeBitCast but you should make a specific struct to call:
#dynamicCallable
struct SumOf {
func dynamicallyCall(withArguments args: [Int]) -> Int {
return args.reduce(0, +)
}
}
let sum = SumOf()
// Use a dynamic method call.
sum(1, 2, 3) // 6
// Call the underlying method directly.
sum.dynamicallyCall(withArguments: [1, 2, 3]) // 6
Related
I want to save a function that takes two parameters as a function that only takes one parameter. I know I learned this with functional programming but I can't remember the methodology name or how to implement it.
Example: a methods like this:
func add (a: Int, b: Int) {
return a + b
}
And you can manipulate and save a new method that let’s say only increments a by 1:
let increment = add(b:1)
print(increment(a: 4))
// prints 5
Can you do this in swift?
It seems you're looking for function currying. This was a part of swift in earlier versions but was removed because it added too much complexity inside the compiler. (Like seen here: https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md)
I guess the closest you can get to a curried function is if you do something like this:
func add(_ x: Int) -> (Int) -> Int {
return { y in
y + x
}
}
With this you can say:
let add2 = add(2)
print(add2(3)) // prints 5
You are looking for Default Parameter Values
You can assign default values to the parameters. When calling this function if you pass the value to the parameters that passed value will be used else the default value will be used. To use the default value you can avoid the parameter in the function calling
func add(a: Int = 1, b: Int = 1) -> Int {
return a + b
}
print(add(a: 5, b: 5))//prints 10
print(add(a: 4))//prints 5
print(add(b: 4))//prints 5
print(add())//prints 2
var a = [1,2,3]
let ptr1 = UnsafeMutablePointer<Int>(&a[0]) //works fine
let index = 0
let ptr2 = UnsafeMutablePointer<Int>(&a[index]) //compiler throws error
error: cannot invoke initializer for type UnsafeMutablePointer<Int> with an argument list of type (inout Int)
Why the latter one doesn't compile? Is there anything I am missing here?
I wanted to do like a below snippet.
class Holder {
var numbers: [Int] = [1,2,3,4]
var modifier: Modifier
init(index: Int) {
self.modifier = Modifier(UnsafeMutablePointer(&self.numbers) + index)
}
}
class Modifer {
var ptr: UnsafeMutablePointer<Int>
init(_ ptr: UnsafeMutablePointer<Int>) {
self.ptr = ptr
}
func change(to: Int) {
self.ptr.pointee = to
// expected the change to be reflected in numbers array
// but as Rob Napier said it became invalid and throws EXC_BAD_ACCESS
}
}
How can I achieve the above expected result?
Note that neither of these is a valid way to create an UnsafeMutablePointer. Swift is free to deallocate a immediately after the last time it is referenced, so by the time you use these pointers, they may be invalid. The tool you want is a.withUnsafeMutableBufferPointer.
That said, the correct syntax here is:
let ptr2 = UnsafeMutablePointer(&a) + index
Looking at your updated code, there's no way for this to make sense on Array. I think you're assuming that Arrays are reference types. They're value types. There's no way to change a piece of numbers. Any change to it replaces the entire array with a completely different array. Swift has some clever copy-on-write tricks to make this efficient, and in practice it may not actually replace the entire array, but you should program as though it did. You should consider the following line:
array[1] = 2
to be equivalent to:
array = <a new array that is identical, but element 1 has been replaced by 2>
This means that pointers into Array are meaningless outside of very controlled situations (such as inside a withUnsafeMutableBufferPointer block).
What you want is something more like this:
class Holder {
var numbers: [Int] = [1,2,3,4]
private(set) var modifier: ((Int) -> ())! // ! is an artifact of capturing self in init
init(index: Int) {
self.modifier = { [weak self] in self?.numbers[index] = $0 }
}
}
let holder = Holder(index: 2)
holder.numbers // [1, 2, 3, 4]
holder.modifier(0)
holder.numbers // [1, 2, 0, 4]
Two faceted question:
var array = [1,2,3,4,5]
contains(array, 0) // false
var array2: NSArray = [1,2,3,4,5]
array2.containsObject(4) // true
Is there any way to search an Array for more than 1 value? ie. Can I write below to search the array for multiple values and return true if any of the values are found? Second part to the question is how can I do that for an NSArray as well?
var array = [1,2,3,4,5]
contains(array, (0,2,3)) // this doesn't work of course but you get the point
You can chain contains together with a second array:
// Swift 1.x
contains(array) { contains([0, 2, 3], $0) }
// Swift 2 (as method)
array.contains{ [0, 2, 3].contains($0) }
// and since Xcode 7 beta 2 you can pass the contains function which is associated to the array ([0, 2, 3])
array.contains([0, 2, 3].contains)
// Xcode 12
array.contains(where: [0, 2, 3].contains)
One option would be to use a Set for the search terms:
var array = [1,2,3,4,5]
let searchTerms: Set = [0,2,3]
!searchTerms.isDisjointWith(array)
(You have to negate the value of isDisjointWith, as it returns false when at least one of the terms is found.)
Note that you could also extend Array to add a shorthand for this:
extension Array where Element: Hashable {
func containsAny(searchTerms: Set<Element>) -> Bool {
return !searchTerms.isDisjointWith(self)
}
}
array.containsAny([0,2,3])
As for the NSArray, you can use the version of contains which takes a block to determine the match:
var array2: NSArray = [1,2,3,4,5]
array2.contains { searchTerms.contains(($0 as! NSNumber).integerValue) }
Explanation of closure syntax (as requested in comments): you can put the closure outside the () of method call if it's the last parameter, and if it's the only parameter you can omit the () altogether. $0 is the default name of the first argument to the closure ($1 would be the second, etc). And return may be omitted if the closure is only one expression. The long equivalent:
array2.contains({ (num) in
return searchTerms.contains((num as! NSNumber).integerValue)
})
Swift 5.7 +
A quick syntax fix to the accepted answer for the latest version of swift:
extension Array where Element: Hashable {
func containsAny(searchTerms: Set<Element>) -> Bool {
return !searchTerms.isDisjoint(with: self)
}
}
I'm trying to build a function with swift that will map an array, divide each value in the array by 3, then spit out a new array. This is what I have so far:
func divideby3Map<T, U>(y: [T], z: T -> U) -> [U] {
let array = [int]()
let divideby3Array = array.map { [y] / 3 }
return dividedby3Array
}
divideby3Map([1,2,3,4,5])
Where T and U are the original array, and the new array being returned respectively, and it's done using generics.
I'm sure this isn't written properly, I'm stuck in terms of the right syntax. For example, since the array being returned is represented by the generic [U], I assume I have to use it somewhere in the array being returned, not sure where though.
When writing a generic function, it’s sometimes easier to approach it in 3 steps: first write the code stand-alone using a specific type. Then write the code as a function, still with a specific type. Finally, change the function to be generic.
The first part, dividing an array by 3, can be done like this:
let a = [1,2,3,4,5]
// map is run on the array of integers, and returns a new
// array with the operation performed on each element in a:
let b = a.map { $0 / 3 }
// so b will be [0,0,1,1,1]
// (don’t forget, integer division truncates)
Note the closure you provide between the { } is an operation that will be applied to each element of the array. $0 represents the element, and you divide it by 3. You could also write it as a.map { i in i / 3 }.
To put this into its own function:
func divideby3Map(source: [Int]) -> [Int] {
return source.map { $0 / 3 }
}
No need to declare a fresh array – map will create one for you. You can then return that directly (you can assign it to a temporary if you prefer, but that isn’t really necessary).
Finally, if you want to make it generic, start by adding a placeholder:
func divideby3Map<T>(source: [T]) -> [T] {
return source.map { $0 / 3 }
}
Note, there’s only a need for one placeholder, T, because you are returning the exact same type you are passed in.
Except… this won’t compile, because the compiler doesn’t know that T is guaranteed to provide two critical things: the ability to divide (a / operator), and the ability to create new T from integer literals (i.e. to create a T with value 3 to divide by). Otherwise, what if we passed an array of strings or an array of arrays in?
To do this, we need to “constrain” T so our function will only accept as arguments types that provide these features. One such protocol we can use to constrain T is IntegerType, which does guarantee these features (as well as some other ones like +, * etc):
func divideby3Map<T: IntegerType>(source: [T]) -> [T] {
return source.map { $0 / 3 }
}
divideby3Map(a) // returns [0,0,1,1,1]
let smallInts: [UInt8] = [3,6,9]
divideby3Map(smallInts) // returns [1,2,3]
I have a method that I'm using to create an array w/ n of a specific type of object in it:
func many(count: Int) -> [Cube] {
var cubes: [Cube] = []
for i in 0...count {
let cube = CubeFactory.single()
cubes.append(cube)
}
return cubes
}
This works but I'm sure there's a more swift like way to do this. Any one know how this can be refactored?
Does CubeFactory.single() actually do anything other than return the same instance every time?
If it does active stuff, return map(0..<count) { _ in CubeFactory.single() } (or numerous variants) will give you an array of them.
(the _ in really oughtn’t to be necessary, but Swift’s type inference gets a bit flummoxed without it and you’ll get an error about half-open intervals – the other possibility for the overloaded ..< operator – not conforming to SequenceType)
If it’s just inert and every cube is identical, return Array(count: count, repeatedValue: Cube.single()) is all you need.
In Swift 2, this is
let array = (0..<30).map { _ in CubeFactory.single() }
Not sure if it's exactly what you're looking for, but you can use:
let array = map(0..<30) { _ in CubeFactory.single() }
Swift 4.2
struct Cube {
let id:Int
}
...
let array = (0..<24).compactMap {
return Cube(id: $0)
}