how to mutate inputting array in-place in swift? [duplicate] - ios

This question already has answers here:
modify an array within a function does not work
(4 answers)
Closed 7 years ago.
Recently I have a piece of code like this:
private func a(var arr1: [Int]) {
arr1.removeRange(0..<2)
}
I thought that adding "var" to arr1 makes it mutable. I eventually notice it's not mutating the inputting array "arr1" after debugging for three hours. I then tried to add the keyword "mutating" to the function, but this gives an error:
'mutating' isn't valid on methods in classes or class-bound protocols
So what is the correct way of mutating arr1 in-place inside the function a()? Is adding "mutating" to the func the way to go? If so, how do I resolve the error message? Thank you.

An Array of Int is a value type, that means the object is copied while being passed to the method.
You can declare the arr1 parameter as inout, that treats the array as reference type:
private func a(inout arr1: [Int]) {
arr1.removeRange(0..<2)
}
var array = [1, 2, 3, 4]
a(&array)
print(array) // [3, 4]
or you have to return the changed array:
private func a(var arr1: [Int]) -> [Int] {
arr1.removeRange(0..<2)
return arr1
}
let array = [1, 2, 3, 4]
let result = a(array)
print(result) // [3, 4]

Related

Use of undeclared type 'Element' In Swift Extension Method (Array)

I am using Generics and protocol to make a name space for my Utils Class. and here when I goes to [Array] , I met some problem . here is the code :
in namespce.swift:
and in Array Extention:
can any one tell me how can i fix it?
Update:
I change my code to :
and here I have another problem , I have use "Self" in the function. but the T: Sequence type has no member of "index" .
Not sure what you are trying to achieve here (and if it's still relevant) but you should constrain your generic to RangeReplaceableCollection (to be able to use remove(at:)) instead of Sequence.
The firstIndex(of:) method (which returns the index of the first matching element) is available on Collection where Element: Equatable.
extension JX_TypeWrapper where T: RangeReplaceableCollection, T.Element: Equatable {
mutating func remove(object: T.Element) {
if let index = SELF.firstIndex(of: object) {
SELF.remove(at: index)
}
}
}
Which allows you to wrap an array into your JX_TypeWrapper:
var array: [Int] = [1, 2, 3]
var wrapped = JX_TypeWrapper(value: array)
wrapped.remove(object: 2)
wrapped.SELF // [1, 3]

UnsafeMutablePointer to an Array element

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]

How to declare a variable to host multiple values [duplicate]

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

Swift search Array/NSArray for multiple values

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)
}
}

Don't understand closures example in Swift

I'm trying to learn about swift and closures.
I'm stuck on this example.
numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})
What is (number: Int) -> Int? Is it a function? Where is it defined?
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-ID1
What does the keyword "in" do? The docs say to use "to separate the arguments and return type from the body". I'm not sure I understand this. Why isn't "in" used to separate "let result = 3 * number" from "return result".
A closure is just a function with the parameters moved inside the brackets, with the keyword in to separate the parameters from the function body. The two following examples define equivalent functions:
func myFunc(number: Int) -> Int {
let result = 3 * number
return result
}
let myClosure = { (number: Int) -> Int in
let result = 3 * number
return result
}
You can actually call them both in exactly the same way:
let x = myFunc(2) // x == 6
let y = myClosure(2) // y == 6
Notice how the second example is exactly the same as the first, only in the first example, the parameters (number: Int) -> Int are outside the brackets, and in the second example the parameters are inside the brackets, followed by the keyword in.
map works by taking an array (numbers, in your example) and creating a new array that is the result of applying the closure function to each element in numbers. So if numbers is [1, 2, 3], the example above will start with 1. It will apply the closure function which will produce a 3 (cuz all it does is multiply the element from the first array by 3). It does that for each element in numbers, until it has produced a new array, [3, 6, 9].
If you wanted to, you could call map using the names of either the above function or the above closure, or by writing it out explicitly inside of map. All of the below examples are totally equivalent:
let numbers = [1, 2, 3]
// Example 1
let times3 = numbers.map(myFunc) // times3 == [3, 6, 9]
// Example 2
let timesThree = numbers.map(myClosure) // timesThree == [3, 6, 9]
// Example 3
let xThree = numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result // xThree == [3, 6, 9]
})
Note that Example 3 is the same as Example 2, only in Example 3 the closure is spelled out explicitly inside of map, whereas in Example 2 the closure has been assigned to a constant called myClosure, and the constant has been supplied to map.
Hope this helps - closures are fun, but confusing.
The function you're calling takes a closure as its parameter:
numbers.map({...})
The closure provided to the function is expected to receive a parameter when it is executed by the function you called. This parameter is defined in your closure:
(number: Int) -> Int in
You may now use the parameter in the contents of the closure
let result = 3 * number
return result
Closures are self-contained blocks of functionality that can be passed around and used in your code.
Syntax:
{(parameterName: ParameterType) -> returnType in
//Statements
}
Practical Scenario: When user want to apply filter and want to select values which is more than 300(in this case) we can use closures to achive this.
var elements: [Int] = [Int]() //Declaring Empty array
elements = [1001, 999, 555, 786, 988, 322, 433, 128, 233, 222, 201, 276, 133]
var filteredElements = elements.map({(num: Int) -> Int? in
return num > 300 ? num : nil
})
output:
[Optional(1001), Optional(999), Optional(555), Optional(786), Optional(988), Optional(322), Optional(433), nil, nil, nil, nil, nil, nil]
From Below code you can clearly see we are passing closure to elements.map() function.
Closure:
{(num: Int) -> Int? in
return num > 300 ? num : nil
}
(num:Int) is parameter.
Int? is we are going to return Optional Integer Type.
After in we can write your logic.
You can read more about closure here.

Resources