numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
Could somebody explain this code? I think numbers is an array here but map is just a function in the swift library right? Like it's a function that already exists and there exists a version of this function that takes an int function that returns an int? Is that it? Well this is a closure I guess and not an int function but can I think of both those as the same as well? Or is a closure and a function different?
You said:
I think numbers is an array ...
Yes, one might infer from the name numbers and from its subsequent usage that it is an array, but you haven't shared its declaration, so technically we cannot be sure. But let us assume for a second that it is an array of integers.
... but map is just a function in the swift library right?
Yes, it is.
Like it's a function that already exists and there exists a version of this function that takes an int function that returns an int?
Technically, not quite. There is not a rendition of map that specifically “takes an int function that returns an int”. It is a “generic” function that just takes a “closure” and returns an array of elements whose type is dictated by the closure return type. In your example, that closure just happens to take an integer and returns an integer (and thus, in this case, map will return an array of those integers). But it just as easily could just be one that returns something else. E.g.,
let numbers = [1, 2, 3]
let strings = numbers.map({ (number: Int) -> String in
return "Value is \(number)"
}
print(strings) // ["Value is 1", "Value is 2", "Value is 3"]
But this is the exact same map function. It is just a question of what closure you supply to it. It is one of the reasons that we use closures, that not only can the application programmer supply their own code to be applied to each element in the array, but they can return whatever type they need for each element, too.
As an aside, consider your example:
let numbers = [1, 2, 3]
let results = numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
First, we would generally use “trailing closure” syntax, eliminating the parentheses:
let numbers = [1, 2, 3]
let results = numbers.map { (number: Int) -> Int in
let result = 3 * number
return result
}
And you might simplify the closure:
let numbers = [1, 2, 3]
let results = numbers.map { (number: Int) -> Int in
return 3 * number
}
And we might let the compiler infer the parameter and return types:
let numbers = [1, 2, 3]
let results = numbers.map { number in
return 3 * number
}
And we might even use “shorthand argument names”, where $0 refers to the first argument, $1 the second, etc. And, when there is only one line of code, you can even omit the return keyword. E.g.,
let numbers = [1, 2, 3]
let results = numbers.map { $0 * 3 }
These are all equivalent to the example you provided in your question. In practice, one would generally use one of these simplified renditions (or a permutation thereof), reducing the amount of syntactic noise in the code.
Related
I am trying to create a function that takes an array of Int, and returns a new array of all of the even numbers in the original array.
I have been fumbling around with this code (I am a very new beginner)
let numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var newArray: [Int] = []
func newInt(newEven: Int, newArray: [Int]) -> Int {
for newEven in numberArray{
var index = 0
index += 1
if newEven % 2 == 0 {
newArray.insert(newEven, at:[index])
}
return newEven
}
}
print(newArray)
This is a good start! Here are some pointers:
1. Formatting
The formatting needs some work. Generally, every new scope ({ ... }) should introduce a new layer of indentation, like so:
let numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var newArray: [Int] = []
func newInt(newEven: Int, newArray: [Int]) -> Int {
for newEven in numberArray{
var index = 0
index += 1
if newEven % 2 == 0 {
newArray.insert(newEven, at:[index])
}
return newEven
}
}
print(newArray)
Now we can make some observations:
1. index is scoped to the for loop body, and will always have the same value of 0, and then 1 after the next line.
2. The return statement is within the for loop body, and unconditional. This function will always return the value of the first element of numberArray
3. The return type of this function is Int. But in your question, you state that you want this to return an array of all of the even numbers. So your return type will have to be Array<Int> (a.k.a. [Int]), not just Int.
2. Compilation issues
This function has several errors that will prevent compilation:
The return statement is within a loop body. If numberArray is empty, and the for loop body is never entered, then you don't hit the return statement. Once control reaches the end of the function, what value should be returned? It's not defined, so that's an error. In Swift, all code paths through a function must return a value. (with the exception of Void functions, which implicitly return nothing at the end)
You're trying to call Array.insert(_:at:) with a second argument of [index], which is an array literal of type Array<Int>. It should just be index.
3. Logical issues
Your function introduces a parameter called newArray, which shadows the global variable newArray on the line before it. The global variable isn't necessary, and you should delete it.
Your function operates over numberArray, but doesn't explicitly take it as input via a parameter. Rather than hardcoding a reference to a global variable like numberArray, you should use a parameter.
The parameter newEven is unused, and is shadowed by the local variable of the for loop
Your function name newInt(newEven:newArray:) doesn't describe what the function does. Consider a function signature like func allEvens(in input: [Int]) -> [Int]
You never actually call this function. You declare it, but never told the program to run it.
You don't need to use Array.insert(_:at:). You can simply use Array.append, which will automatically append elements to the end of the array.
4. Recommendations
Fix the method signature. You want the function to take some numbers, and output only the even numbers. Model that in code: func allEvens(in input: [Int]) -> [Int]
Create a new empty array locally (within the function), into which the even numbers will be stored. As you loop over the input array, check every number if it's even, and if so, append it to the evens array.
Return the evens array.
let numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var newArray = numberArray.filter({$0 % 2 == 0})
This should return a new array with even numbers.
As LeoDabus mentioned in his comment, the functionality you're seeking is already contained within Swift's Standard Library, so it's not really necessary to write a dedicated function to accomplish that task. Here's how you would do it:
let numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let newArray = numberArray.filter { $0.isMultiple(of: 2) }
print(newArray) // [2, 4, 6, 8, 10]
In this, you're using the filter whether $0 (where $0 is an element in your array) is a multiple of the number you specified in the parameter, in this case, 2.
As you see in the documentation, isMultiple(of:) returns a Bool (true or false). This is the signature:
func isMultiple(of other: Self) -> Bool
I would recommend having a peek at this post covering the topics of map, filter, and reduce. These are useful things to know when starting out in Swift.
Additionally, I've found Dash to be extremely helpful in navigating documetation for Swift.
Update
I should have read your question more thoroughly, as I missed the part where you've gotta do it with a loop. Swift has a cool method called forEach, which I'm a huge fan of. Using that methodology, it would look something like this:
func filter(array: [Int], forMultiplesOf multiple: Int) -> [Int] {
// Create a landing spot for whatever is a multiple...it starts as empty
var newArray: [Int] = []
// This is not the most compact way, but it satisfies the loop constraint
array.forEach { number in
if number % multiple == 0 {
newArray.append(number)
}
}
// Once you're done with the loop, then return the new array you declared at the beginning
return newArray
}
And you'd call it like so:
let newArrayUsingFunction = filter(array: numberArray, forMultiplesOf: 2)
What you're doing here is passing in 2 parameters to the function (array & multiple) to return an array of Ints. See comments in code for what's going on
I've just stared learning swift and got stuck with functions. could someone help?
Also, I would be grateful if you could suggest me some books about Swift for beginners with simple exercises so i could practise. Thanks in advance)
There already is such a function. It's called map. It takes a closure that takes each element of the source array as input and returns a new value to use in the output array.
let ints = [1, 3, 5, 7, 9, 23, 57]
let doubled = ints.map { return $0 * 2 }
alternately, you could write your own function that takes an array of ints and returns another array of Ints:
func doubledInts(_ array: [Int]) -> [Int] {
var output = [Int]()
for value in array {
output.append(value *2)
}
return output
}
You could also get fancier, and make your function use Generics to take any scalar value (Int and it's variants like Int32, UInt32, Int8, plus Double, Float, etc) and return an array of the same type, but if you don't yet understand the basics of functions then Generics are going to be way over your head.
I learned Swift from the Apple iBook "The Swift Programming Language." I found it very informative, but your milage may vary.
First of all, this question is not about "what does $0 mean". I learnt in swift document that $0 is like index.
My question is "How numbers.sort { $0 > $1 } can be used to implement a sort function". I searched for this syntax numbers.sort { $0 > $1 } in some other websites, for example this one. It is apparently not the current version. So I still can't understand what the meaning of it.
print(numbers) //[20, 19, 1, 12]
let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers) //[20, 19, 12, 1]
Can someone explain this simple piece of code above for me? Like how this simple code $0 > $1 implement the sort function, sorting the numbers from big to small.
I know some about index, and this $0 looks like index, but it only has $0 and $1 two indices. So how can it be used into 4 numbers? According to my knowledge in C++ before, I can't understand the principle in this.
Please make your answer as specific as possible. Thank you!
----------------- Below is edited extra part -------------------
I don't know whether stackoverflow would allow me to edit my question like this, but this extra part is too long, so I can't add it in the comment.
#pbodsk #Paul Richter
So the sort() syntax in swift uses quick sort to deal with sort function?
Actually my question is more about "what is the operating principle of sort{$0 > $1}". I know what you mean above, and I think it's similar with what swift 2.1 document says, but your answer is not what I really want to know. Sorry, my English expression is not very good. Let me try another way.
When I learnt C++ before, there are always some documents to explain what a function's operating principle is or how this function (like sort() here) operate in background. Sort() here needs to compare first and second interchange. In C++, it's like
if numbers[1] < numbers[2]{ //just consider this pseudocode
int k;
k = numbers[1];
numbers[1] = numbers[2];
numbers[2] = k;
}
We can see this process is obvious. In swift, it's like
numbers.sort({(val1: Int, val2: Int) -> Bool in
return val1 > val2
})
Where is it compared? And how is it interchanged? Does return val1 > val2 automatically compare and interchange these two values and return them? Just this one syntax implement these all 3 processes? How? This is what I really want to know. Sorry again for my poor English expression.
#the_UB and #moonvader are both right, but I just thought that I would extend the example from #moonvader a bit, just to show you how we end up with $0 > $1
If you look at the example in "The Swift Programming Language" about Closure Expressions you can see that to sort an array you call the sort method which can then take a function as a parameter.
This function must take two parameters and compare them, and then return a boolean.
So if we have this array:
let numbers = [4, 6, 8, 1, 3]
and this method
func sortBackwards(val1: Int, val2: Int) -> Bool {
print("val1: \(val1) - val2: \(val2)" )
return val1 > val2
}
We can sort the elements like so:
numbers.sort(sortBackwards) //gives us [8, 6, 4, 3, 1]
The sort method will use our sortBackwards method on each of the elements in the array and compare them.
Here's the output of the print
val1: 6 - val2: 4
val1: 8 - val2: 4
val1: 8 - val2: 6
val1: 1 - val2: 4
val1: 3 - val2: 1
val1: 3 - val2: 4
OK, let's reduce that.
Instead of defining a function, we can add that directly as a parameter to the sort method like so:
numbers.sort({(val1: Int, val2: Int) -> Bool in
return val1 > val2
})
And we still end up with [8, 6, 4, 3, 1] (how fortunate!)
OK, the next thing we can do is what in "The Swift Programming Language" (the link above) is called "Infering Type From Context". As we call this method on an array of Ints, Swift can figure out that our val1 and val2 parameters must be Ints too, there's no need for us to tell it. So, lets remove the types. That leaves us with:
numbers.sort({val1, val2 in
return val1 > val2
})
And still the same result.
OK, getting there. The next thing we can do is what in the book is called "Implicit Returns from Single-Expression Closures"
As our comparison can be done in one line there's no need for us to use return. So:
numbers.sort({val1, val2 in val1 > val2})
Still gives us [8, 6, 4, 3, 1]
Finally we're getting to what #moonvader used much much less words to explain :-) namely "Shorthand Argument Names"
As it says in the book:
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
So, in our example, val1 can be replaced by $0 and val2 can be replaced by $1
Which gives us:
numbers.sort({$0 > $1})
And still we get [8, 6, 4, 3, 1]
We can then continue to use a "Trailing Closure", which means that if the last parameter of a function is a closure, we can add that parameter "outside" the function.
So we end up with:
numbers.sort{$0 > $1}
And the outcome is still [8, 6, 4, 3, 1]
Hope that helps to clarify things.
Here is what all need to know: Sort and Sorted.
To be more specific, Sorting can be two type : Ascending and Descending.
Q - So to do sorting, what do we need?
A - We need two variables to hold two variable(I don't know if it is the correct word)
Hence in this case we have two variable $0 and $1. These both are shorthands to represent left and right variable. Both will help to sort.
">" will do descending.
"<" will do ascending.
From developer.apple.com
Shorthand Argument Names
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body:
reversed = names.sort( { $0 > $1 } )
Here, $0 and $1 refer to the closure’s first and second String arguments.
The process of sorting a list consists of repeatedly reordering its elements until nothing remains to be reordered. Now there are many sorting algorithms, but they all do this, in different ways. So then how are elements reordered? By comparing two given elements, and deciding which comes first, and swapping them if needed.
We can separate the overall reordering and swapping parts from the comparison part, and write a sort function that will take care of all the repeated reordering stuff, and just require the caller to specify how to compare two elements. If the list consists of numbers, it's almost always the case that the way to compare them is to just take their value. But suppose the list consists of things a little more complicated, like cars. How do you compare two cars? Well, you could compare them by numerically comparing their top speed. Or their gas mileage. Or price.
But the comparison doesn't have to be numerical. We could compare two cars by actually racing them. We could compare two cars by just saying if one is blue and the other isn't, the blue one is ordered first, and if neither or both are blue they are ordered as they already are.
We could come up with all sorts of ways to compare two cars. And the sorting algorithm could then sort a list of cars, without knowing anything about cars, as long as we the caller just tell it how to compare cars - any two given cars. We just have to express that comparison as an expression that returns a boolean, where if it's true, the first car is ordered before the second one, and if it's false, the first car is ordered after the second one.
Returning to numbers, that's what sort { $0 > $1 } means, in Swift's very concise syntax: "Sort, where if the first element is > the second one, order the first one before the second one."
You asked how it can sort four numbers with only two indices. $0 and $1 are not bound to the four specific elements in the list [20, 19, 1, 12], they are bound to any two given numbers that need to be compared, because the sorting algorithm repeately needs to do this.
There are a few things to note. First, the operator > has to be defined for the kinds of elements you are sorting. In the example the elements are numbers, and > is indeed defined. Second, the sort function specifies that the boolean true orders the first one before the second rather than the other way around, so the comparison function follows that specification. Third, the last evaluated expression is taken as the boolean value to be used. Having these two assumptions beforehand allows the comparison function to be written so concisely.
So if we wanted to sort those cars by racing them, we could write it like this:
cars.sort {
winner_of_race_between($0, $1) == $0
// if the first car beats the second, it is sorted ahead
}
Or exclusive blueness:
cars.sort { //not guaranteed to be valid Swift, just consider this pseudocode
if(($0.color != Color.blue) && ($1.color == Color.blue) {
$1
} else if (($0.color == Color.blue) && ($1.color != Color.blue)) {
$0
} else { //leave them in same order
$0
}
}
extension Array {
public func mySorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element] {
var newArray: [Element] = self
if newArray.count <= 1 {
/// nothing to do
} else if newArray.count <= 32 { /// 32 ?? 64
for l in 1..<count {
for r in (0..<l).reversed() {
if try areInIncreasingOrder(newArray[r + 1], newArray[r]) {
(newArray[r + 1], newArray[r]) = (newArray[r], newArray[r + 1])
} else {
break
}
}
}
} else {
/// others sort
}
return newArray
}
}
var array: [Int] = [4, 6, 8, 1, 3]
let a1 = array.sorted {
print("\($0) \($1)")
return $0 > $1
}
print("---------")
let a2 = array.mySorted {
print("\($0) \($1)")
return $0 > $1
}
print("==========")
let a1 = array.sorted {
print("\($0) \($1)")
return $0 < $1
}
print("+++++++")
let a2 = array.mySorted {
print("\($0) \($1)")
return $0 < $1
}
I read "The swift programming language" and the subscript make me confused, there's a example below with subscript, but I could also implement it with a function, so what the subscript exactly mean compared with function?
There were same output "6 times 3 is 18" with below example.
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
println("6 times 3 is \(threeTimesTable[6])")
struct TimesTable2 {
let multiplier: Int
func times (index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable2 = TimesTable2(multiplier: 3)
println("6 times 3 is \(threeTimesTable2.times(6))")
Subscripts are a subset of functions. They can't quite do all the things a function can do (they can't take inout parameters, for instance), but they do other things very well, with a very convenient syntax (the square brackets [ ]).
They are most often used to retrieve an item from a collection by its index. So instead of having to write,
let array = [7, 3, 6, 8]
let x = array.itemAtIndex(0) // x == 7
we can just write,
let x = array[0]
Or instead of,
let dictionary = ["one": 1, "two": 2]
let x = dictionary.objectForKey("one") // x == Optional(1)
we can just write,
let x = dictionary["one"] // x == Optional(1)
The syntax is short and intuitive. And as Okapi said, they can act as getters and as setters for variable properties, just like a computed property.
The example in the documentation is a somewhat non-traditional use of subscripts. I think it is supposed to illustrate the very point that you are making - subscripts can be used in place of a function or a computed property just about anywhere that you think the [bracket] syntax would be convenient and useful. Their use is not limited to accessing items in a collection.
You get to refine your own syntactic sugar.
I'm in the process of getting comfortable passing unnamed functions as arguments and I am using this to practice with, based off of the examples in the Swift Programming Guide.
So we have an array of Ints:
var numbers: Int[] = [1, 2, 3, 4, 5, 6, 7]
And I apply a transform like so: (7)
func transformNumber(number: Int) -> Int {
let result = number * 3
return result
}
numbers = numbers.map(transformNumber)
Which is equal to: (7)
numbers = numbers.map({(number: Int) -> Int in
let result = number * 3
return result;
})
Which is equal to: (8)
numbers = numbers.map({number in number * 3})
Which is equal to: (8)
numbers = numbers.map({$0 * 3})
Which is equal to: (8)
numbers = numbers.map() {$0 * 3}
As you can see in the following graphic, the iteration count in the playground sidebar shows that in the furthest abstraction of a function declaration, it has an 8 count.
Question
Why is it showing as 8 iterations for the last two examples?
It's not showing 8 iterations, really. It's showing that 8 things executed on that line. There were 7 executions as part of the map function, and an 8th to do the assignment back into the numbers variable.
It looks like this could probably provide more helpful diagnostics. I would highly encourage you to provide feedback via https://bugreport.apple.com.
Slightly rewriting your experiment to use only closures, the call counts still differ by one:
Case 1: Explicitly specifying argument types (visit count is 7)
var f1 = {(number: Int) -> Int in
let result = number * 3
return result
}
numbers.map(f1)
Case 2: Implicit argument types (visit count is 8)
var f2 = {$0 * 3}
numbers.map(f2)
If the (x times) count reported by the REPL does indeed represent a count of visits to that code location, and noting that the count is greater by one in cases where the closure type arguments are not explicitly specified (e.g. f2), my guess is that at least in the playground REPL, the extra visit is to establish actual parameter types and fill that gap in the underlying AST.