Passing func as param Swift - ios

I am moving through the Swift Programming Language Book and I don't fully understand this:
//I don't understand 'condition: Int -> Bool' as a parameter, what is that saying?
func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
//So here i see we are iterating through an array of integers
for item in list {
//I see that condition should return a Bool, but what exactly is being compared here? Is it, 'if item is an Int return true'??
if condition(item) {
return true
}
}
return false
}
//This func I understand
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 20]
hasAnyMatches(numbers, lessThanTen)
If you could explain a little more of what exactly is going on here it would be much appreciated. I ask most of the question in the comments so it's easier to read but the main thing confusing me is condition: Int -> Bool as a parameter.

As it states in the book, the second argument is a function (what's actually going on I've explained in code comments)
// 'condition: Int -> Bool' is saying that it accepts a function that takes an Int and returns a Bool
func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
// Takes each item in array in turn
for item in list {
// Here each 'item' in the list is sent to the lessThanTen function to test whether the item is less than 10 and returns true if it is the case and executes the code, which in turn returns true
if condition(item) {
return true
}
}
return false
}
// This function is sent as the second argument and then called from hasAnyMatches
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 20]
hasAnyMatches(numbers, lessThanTen)
In the scenario provided, the loop will continue to run until it hits 7, at which point true will be returned. If there was no number beneath 10 then the function would return false.

condition: Int -> Bool is the syntax for you to pass in a closure, more commonly known as functions.
The function lessThanTen has a type of Int -> Bool, as can be seen from its signature
inputTypes->outputType is basically all you need to define a function!
It should work like this as well:
hasAnyMatches(numbers, { number in ; return number < 10 } )
// Or like this, with trailing closure syntax
hasAnyMatches(numbers) {
number in
return number < 10
}

Related

Is my recursive function failing due to a stack overflow? If yes, given my function definition, is it normal?

I was testing a recursive function for performance.
In line 33, I create an array with 50,000 items in it; each item in the array is an Int between 1 & 30.
The test crashes when the array has a count approximately > 37500.
I’m not exactly sure what this crash is due to, but my guess is that it’s due to a stack overflow?
Is it in fact due to stackover flow?
Given what I’m doing / this context - is a stack overflow here normal to expect?
The code is provided below for your convenience:
let arr = (1...50000).map { _ in Int.random(in: 1...30) }
func getBuildingsWithView(_ buildings: [Int]) -> [Int]? {
if buildings.isEmpty { return nil }
let count: Int = buildings.count - 1
var indices: [Int] = []
let largest: Int = 0
var buildings = buildings
hasView(&buildings, &indices, largest, count)
return indices
}
func hasView(_ buildings: inout [Int], _ indices: inout [Int], _ largest: Int, _ count: Int) {
if count > 0 {
var largest = largest
if (buildings[count] > largest) {
largest = buildings[count]
}
hasView(&buildings, &indices, largest, count-1)
}
if (buildings[count] > largest) {
indices.append(count)
}
}
func test1() {
print("-----------------TEST START - RECURSION------------------")
measure {
print(getBuildingsWithView(arr)!)
}
print("-----------------END------------------")
}
This is likely a stack overflow, function hasView is called cursively with a depth roughly equal to count and the stack has to store count adresses which could exceed the stack size for huge numbers.
More details in another post: BAD_ACCESS during recursive calls in Swift
Please note that what you implemented seems to be a running maximum in reverse order returning the indices and this can implemented more efficiently without overflow like this:
func runningMax(_ arr: [Int]) -> [Int] {
var max = 0
var out = [Int]()
for (i, element) in arr.enumerated().reversed() {
if element > max {
max = element
out.append(i)
}
}
return out.reversed()
}
I compared this with your algorithm and the outputs seems to be identical. I also tested with larges values up to 100,000,000 and it is fine.
Returned array does not need to be optional, if the input array is empty so do the output array.

iOS Swift 4 Extension Range

How can return an Int from a range of numbers in Swift?
I want to return an Int from a range of two numbers. Ultimately my goal is to assign the returned Int value to an indexPath.row of a tableview in cellforpathatindex method. I have written the extension but when I print the return value which is in the example below is k, I am only getting the min value instead of the entire range of values.
extension Range {
func returnIndexValue(min: Int, max: Int) -> Int {
var indexArray = [Int]()
let range = (min..<max)
for i in range {
return i
}
for p in indexArray {
return p
}
return max
}
}
let range: Range<Int> = 1..<10
var k = range.returnIndexValue(min: 6, max: 100)
print(k)
if you want to return all the range of int values in an array then you can do it like that :
func returnIndexValue(min: Int, max: Int) -> [Int] {
return Array(min...max)
}
And you don't need to use an extension for that.
Your function terminates at the first return it hits which is when it returns min in the first loop.
Edit
Your comments show you still don't get the problem with your code. A return statement exits the function. If you have a return in a loop as you do, the loop and the function are exited, the first time you execute the return. There's no way to magically go back and continue executing the loop. You're done.
Do you want a sequence of all the numbers in the range? Because a Range of Int is already a sequence. So you can create an array of all the values in the range simply by doing this:
let arrayOfInts = Array(1 ..< 4) // [ 1, 2, 3 ]
Your for ... in statement already does what you need, just replace the return with whatever it is you want to do for each value. For example:
for i in range
{
print(i)
}
prints all the numbers from min to max - 1

Swift error, cannot convert type Int to int 16

This function compares the number with the sum of the cubes of the components of this number. For example abc=a^3 + b^3 + c^3. There is an error converting, please help.
func triKuba ( i:Int16, k:Int16, var array:[Int16]=[] ) ->Int16{
for var i=100;i<1000; i++ {
array.append(Int16(i))
if array[i] == pow(array[i]/10) + pow(array[i]/100) + pow(array[i]%10) {
return array[i]
} else {
return 0
}
}
}
triKuba(0, k: 0)
next error in line around method pow 'Cannot invoke pow with argument list of type Int16' if I understood correctly, method pow is a^3
I strongly suspect this is what you are looking for:
func arithmeticRoot3(var value: Int) -> Int {
var result = 0
while value > 0 {
let digit = value % 10
result += digit * digit * digit
value /= 10
}
return result
}
func triKuba() -> [Int] {
return (100...999).filter() {
$0 == arithmeticRoot3($0)
}
}
print(triKuba()) // [153, 370, 371, 407]
Rather than just solving your issue, I'm going to explain what the problem is, and why it throws an error. With this information you should be able to fix the issue (and similar ones in the future!).
In Swift, you can't always do things like multiply an Int with a Float, or return an Int16 from a Double type return function. To you, it might be obvious that 'casting' the variable to the intended type would be fine - but the compiler doesn't know that.
If you're sure it will be safe, you can 'cast' variables to the required type:
Int(int16Variable) // int16Variable has been casted to an 'Int'.
The method you posted had several syntax issues. I fixed them. Working method below:
func triKuba ( i:Int16, k:Int16, var array:[Int16]=[] ) ->Int16{
for var i=100;i<1000; i++ {
array.append(Int16(i))
if Double(array[i]) == pow(Double(array[i])/10, 3.0) + pow(Double(array[i]/100), 3.0) + pow(Double(array[i]%10), 3.0) {
return array[i]
} else {
return 0
}
}
}
Error you were getting was about missing cast from Int to Int16(i)
in your for loop you are declaring a new i variable which is implied to be of type Int as opposed to Int16. (Due to shadowing this is the variable being used in your function body, the parameter i you pass in is never being used.
I would advise either changing the type for your function parameters to be of type Int like so:
func triKuba (var i: Int, var k: Int, var array: [Int]=[] ) -> Int {
or cast your Int16 variables to Ints like so:
array.append(Int16(i))

iOS 9 Stanford Course in Swift - Lecture 1

I'm currently trying to complete the Swift Course on iTunes U and we are building a calculator. I'm having trouble understanding part of the code.
I added the code below that I thought was relevant from the file.
Here is what confuses me: why does operation(operand) compute the value for the UnaryOperation (i.e. the square root)? I see that when the CalculatorBrain class is called the dictionary is initialized, but when I print the dictionary out I just get something that looks like this: [✕: ✕, -: -, +: +, ⌹: ⌹, √: √]. So where/when does the program compute the square root when I click on the square root button?
Class CalculatorBrain
{
private enum Op: Printable
{
case Operand(Double)
case UnaryOperation(String, Double -> Double)
case BinaryOperation(String, (Double, Double) -> Double)
var description: String {
get {
switch self {
case .Operand(let operand):
return "\(operand)"
case .UnaryOperation(let symbol, _):
return symbol
case .BinaryOperation(let symbol, _):
return symbol
}
}
}
}
private var opStack = [Op]()
private var knownOps = [String: Op]()
init() {
func learnOp(op: Op) {
knownOps[op.description] = op
}
learnOp(Op.BinaryOperation("✕", *))
learnOp(Op.BinaryOperation("⌹") { $1 / $0 })
learnOp(Op.BinaryOperation("+", +))
learnOp(Op.BinaryOperation("-") { $0 - $1 })
learnOp(Op.UnaryOperation ("√", sqrt))
}
private func evaluate(ops: [Op]) -> (result: Double?, remainingOps: [Op])
{
if !ops.isEmpty {
var remainingOps = ops
let op = remainingOps.removeLast()
switch op {
case .Operand(let operand):
return (operand, remainingOps)
case .UnaryOperation(_, let operation):
let operandEvaluation = evaluate(remainingOps)
if let operand = operandEvaluation.result {
**return (operation(operand), operandEvaluation.remainingOps)**
}
// case.BinaryOperation(.....)
}
}
return (nil, ops)
}
func evaluate() -> Double? {
let (result, remainder) = evaluate(opStack)
return result
}
func pushOperand(operand: Double) -> Double? {
opStack.append(Op.Operand(operand))
return evaluate()
}
func performOperation(symbol: String) -> Double? {
if let operation = knownOps[symbol] {
opStack.append(operation)
}
return evaluate()
}
}
The Op enum implements the Printable protocol, which means it has a description: String property. When you print the Dictionary, you are sending [String : Op] to the println function which then tries to print the Op using its description.
The reason the description of the operators is the same as its key in the Dictionary is because the learnOp(op: Op) function sets the key to be op.description (knownOps[op.description] = op)
To see the effects of this, you could add a new operator learnOp(Op.UnaryOperation ("#", sqrt)) which will be printed as #:# inside of the knownOps Dictionary. (And if you add a new button for the # operator, it will also perform the square root operation)
Since the calculator is stack based, the operands get pushed on, then the operations. When evaluate() gets called, it calls evaluate(opStack) passing the entire stack through.
evaluate(ops: [Op]) then takes the to item off of the stack and evaluates the function after having calculated the operands.
As an example, lets say you want to calucalte sqrt(4 + 5).
You would push the items onto the stack, and it would look like: [ 4, 5, +, sqrt ]
Then evaluate(ops: [Op]) sees the sqrt and evaluates the operand with a recursive call. That call then evaluates + with two more recursive calls which return 5 and 4.
The tree of calls would look like this:
ops: [4, 5, +, sqrt] // Returns sqrt(9) = 3
|
ops: [4, 5, +] // Returns 4 + 5 = 9
____|_____
| |
ops: [4, 5] ops: [4]
return 5 return 4
I strongly recommend you put a breakpoint on the evaluate() -> Double? function and step through the program to see where it goes with different operands and operations.
learnOp(Op.UnaryOperation ("√", sqrt))
sqrt is a built in function, so you're teaching the calculator that "√" means it should perform the sqrt operation.

Counting number of Arrays that contain the same two values

Given a Dictionary<String, Arrary<Int>> find the how many entries have the same two specified values in the first 5 entries in the Array<Int>.
For example:
Given:
let numberSeries = [
"20022016": [07,14,36,47,50,02,05],
"13022016": [16,07,32,36,41,07,09],
"27022016": [14,18,19,31,36,04,05],
]
And the values: 7 and 36, the result should be 2 since the first and second entry have both the values 7 and 36 in the first 5 entries of the entry's array.
I've tried to accomplish this many ways, but I haven't been able to get it to work.
This is my current attempt:
//created a dictionary with (key, values)
let numberSeries = [
"20022016": [07,14,36,47,50,02,05],
"13022016": [16,07,32,36,41,07,09],
"27022016": [14,18,19,31,36,04,05],
]
var a = 07 //number to look for
var b = 36 // number to look for
// SearchForPairAB // search for pair // Doesn't Work.
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
for number in numbers[0...4] {
if number == ab { //err: Cannot invoke '==' with argument listof type Int, #Value [Int]
abPairApearedCount++
}
}
}
This gives the error: Cannot invoke '==' with argument listof type Int, #Value [Int] on the line: if number == ab
You can't use == to compare an Int and Array<Int>, that just doesn't make any sense from a comparison perspective. There are lots of different ways you can achieve what you're trying to do though. In this case I'd probably use map/reduce to count your pairs.
The idea is to map the values in your ab array to Bool values determined by whether or not the value is in your numbers array. Then, reduce those mapped Bools to a single value: true if they're all true, or false. If that reduced value is true, then we found the pair so we increment the count.
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
let found = ab.map({ number in
// find is a built-in function that returns the index of the value
// in the array, or nil if it's not found
return find(numbers[0...4], number) != nil
}).reduce(true) { (result, value: Bool) in
return result && value
}
if found {
abPairApearedCount++
}
}
That can actually be compacted quite a bit by using some of Swift's more concise syntax:
var ab = [a,b] // pair to look for
var abPairApearedCount = 0
for (kind, numbers) in numberSeries {
let found = ab.map({ find(numbers[0...4], $0) != nil }).reduce(true) { $0 && $1 }
if found {
abPairApearedCount++
}
}
And, just for fun, can be compacted even further by using reduce instead of a for-in loop:
var ab = [a,b] // pair to look for
var abPairApearedCount = reduce(numberSeries, 0) { result, series in
result + (ab.map({ find(series.1[0...4], $0) != nil }).reduce(true) { $0 && $1 } ? 1 : 0)
}
That's getting fairly unreadable though, so I'd probably expand some of that back out.
So here's my FP solution, aimed at decomposing the problem into easily digestible and reusable bite-sized chunks:
First, we define a functor that trims an array to a given length:
func trimLength<T>(length: Int) -> ([T]) -> [T] {
return { return Array($0[0...length]) }
}
Using this we can trim all the elements using map(array, trimLength(5))
Now, we need an predicate to determine if all the elements of one array are in the target array:
func containsAll<T:Equatable>(check:[T]) -> ([T]) -> Bool {
return { target in
return reduce(check, true, { acc, elem in return acc && contains(target, elem) })
}
}
This is the ugliest bit of code here, but essentially it's just iterating over check and insuring that each element is in the target array. Once we've got this we can use filter(array, containsAll([7, 26])) to eliminate all elements of the array that don't contain all of our target values.
At this point, we can glue the whole thing together as:
filter(map(numberSeries.values, trimLength(5)), containsAll([7, 36])).count
But long lines of nested functions are hard to read, let's define a couple of helper functions and a custom operator:
func rmap<S:SequenceType, T>(transform:(S.Generator.Element)->T) -> (S) -> [T] {
return { return map($0, transform) }
}
func rfilter<S:SequenceType>(predicate:(S.Generator.Element)->Bool) -> (S) -> [S.Generator.Element] {
return { sequence in return filter(sequence, predicate) }
}
infix operator <^> { associativity left }
func <^> <S, T>(left:S, right:(S)->T) -> T {
return right(left)
}
And a convenience function to count it's inputs:
func count<T>(array:[T]) -> Int {
return array.count
}
Now we can condense the whole thing as:
numberSeries.values <^> rmap(trimLength(5)) <^> rfilter(containsAll([7, 36])) <^> count

Resources