I am learning swift coming from a Haskell background, I would like to translate this bit into swift:
match :: Int -> Bool
match = (>) 3
hasMatch :: (Int -> Bool) -> [Int] -> [Int]
hasMatch pred ns = filter pred ns
hasMatch match [1..5] = [4,5]
Silly example I know. This is what I have with swift:
func hasMatch(pred : (Int) -> Bool, ns : [Int]) -> [Int]{
return ns.filter{n in pred(n:n)}
}
func match(n: Int) -> Bool{
return n > 3
}
let os = hasMatch(pred : match, ns: [1,2,3,4,5])
Which does not compile. This is the error message:
let os = hasMatch(pred : match, ns: [1,2,3,4,5])
./hello-swift.swift:48:28: error: extraneous argument label 'n:' in call
return ns.filter{n in pred(n:n)}
^~~
./hello-swift.swift:48:24: error: closure use of non-escaping parameter 'pred' may allow it to escape
return ns.filter{n in pred(n:n)}
^
./hello-swift.swift:47:15: note: parameter 'pred' is implicitly non-escaping
func hasMatch(pred : (Int) -> Bool, ns : [Int]) -> [Int]{
^
#escaping
I have two questions:
I have pred(n:n) but this assumes that pred names its input as n, which does not make sense. Do all functions have to have named inputs?
How would I change to the code so that it compiles
func hasMatch(pred: (Int) -> Bool, ns: [Int]) -> [Int] {
return ns.filter { n in pred(n) }
}
You don't need parameter names if the function is a closure.
#escaping is a keyword in swift which tells the compiler that the passed in function will escape the current scope, so it needs to retain/release the passed in arguments (Swift, like objective-c, uses retain counting for memory management)
However, you don't need it in this case - that error was a red herring thrown by the compiler because it couldn't compile the line with filter in, so it didn't know whether you needed to escape or not. Looks like it plays things safe :)
As soon as you remove the n: and it can work out which filter you are calling, it knows that because filter doesn't need an #escaping closure, your method doesn't either so that error goes away.
func mapedData(){
let bookData = ["book1":120, "book2": 150]
let mapedData = bookData.map({(key,value) in return value + 40 })
print(mapedData)
}
// [160, 190]
func filterData()
{
let bookData = ["book1":127, "book2": 150 ,"book3": 289 ,"book4": 190, "book5": 950 ]
let filterData = bookData.filter({(key,value) in return value < 200})
print(filterData)
}
// ["book2": 150, "book4": 190, "book1": 127]
func reducedData()
{
let data = [1,2,3,4,5,6,7,8,9,10]
let reducedData = data.reduce(0, { sum , number in return sum + number })
print(reducedData)
}
//55
func compactData(){
let data = [1,nil,3,4,5,6,7,nil,9,10]
let cMap = data.compactMap({return $0})
print(cMap)
}
// [1, 3, 4, 5, 6, 7, 9, 10]
func flatMappedData(){
let data = ["sachin"]
let characters = data.flatMap({return $0})
print(characters)
}
// ["s", "a", "c", "h", "i", "n"]
Related
I am beginner in swift and I'm doing exercises to learn.
I have to filter any numbers that are even, sort the array, map them to string and print the result one item per line.
The problem is, when I call the function, I´m not able to chain the closures, and it only prints the third function.
import Foundation
let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]
func doImportantWorkChain (first: ([Int]) -> [Int], second: ([Int]) -> [Int], third: ([Int]) -> [String]) {
first(luckyNumbers)
second(luckyNumbers)
third(luckyNumbers)
third(luckyNumbers).forEach {
print($0)
}
}
doImportantWorkChain { number in
return number.filter {
return $0.isMultiple(of: 2)
}
} second: { number in
return number.sorted {
return $0 < $1
}
} third: { number in
return number.map {
("\($0) is the lucky number")
}
}
Output
7 is the lucky number
4 is the lucky number
38 is the lucky number
21 is the lucky number
16 is the lucky number
15 is the lucky number
12 is the lucky number
33 is the lucky number
31 is the lucky number
49 is the lucky number
Output I have to get
4 is the lucky number
12 is the lucky number
16 is the lucky number
38 is the lucky number
I know that I have to use: luckyNumbers.first { }.second { }
When I try to write like this Xcode give me error: value of type '(([Int]) -> [Int], ([Int]) -> [Int], ([Int]) -> [String]) -> ()' has no member 'first'
So I erase first and give me this errors:
Expected member name following '.'
Top-level statement cannot begin with a closure expression
Value of type '(_) -> _' has no member 'second'
doImportantWorkChain.first{ number in
return number.filter {
return $0.isMultiple(of: 2)
}
}.second{ number in
return number.sorted {
return $0 < $1
}
}.third{ number in
return number.map {
("\($0) is the lucky number")
}
}
Also I try to chain it when when I call them inside the function but doesn't work either.
As the first answer suggested, the issue is that the result of a closure should be used in the next closure.
The fastest way to get the output you are looking for
func doImportantWorkChain(first: ([Int]) -> [Int],
second: ([Int]) -> [Int],
third: ([Int]) -> [String]) {
third(second(first(luckyNumbers))).forEach {
print($0)
}
}
However, this is not really chaining functions together and it is doing what the first answer with and just reduces your lines of code but there is no real upgrade in this.
The right way (IMO) to get the output you are looking for
Chaining would be something that I believe one of the commenters suggested is using the filter, sort and map functions directly on luckyNumbers to get your desired output:
luckyNumbers
.filter { $0.isMultiple(of: 2) }
.sorted() { return $0 < $1 }
.map { ("\($0) is the lucky number") }
.forEach { print($0) }
A way that is chaining, will give you the desired output but I don't know why you would ever use this
If you think about what you need to do, to achieve some sort of chaining, you need to create your own higher order functions like filter, map etc with the same signatures as your closures and then executing the closures.
I did this by creating an extension for Int arrays
extension Array where Element == Int
{
func apply(_ operation: ([Int]) -> [Int]) -> [Int]
{
return operation(self)
}
func apply(_ operation: ([Int]) -> [String]) -> [String]
{
return operation(self)
}
}
Then you can achieve chaining and get your desired result
func doImportantWorkChain(first: ([Int]) -> [Int],
second: ([Int]) -> [Int],
third: ([Int]) -> [String]) {
luckyNumbers
.apply(first)
.apply(second)
.apply(third)
.forEach { print($0) }
}
Again, this might be a nice exercise to work your brain and explore the language and its capabilities but I don't think you will ever really use this.
All three of the above ways will give you this output:
4 is the lucky number
12 is the lucky number
16 is the lucky number
38 is the lucky number
You are not using results from previous functions to next.
If you do so then you will end up with error on this third(luckyNumbers).forEach line as function expected [Int] and you will be going to pass [String] as output from this third(luckyNumbers) call.
To work this code, you can have following modifications and run
let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]
func doImportantWorkChain (first: ([Int]) -> [Int], second: ([Int]) ->
[Int], third: ([Int]) -> [String]) {
let first_result = first(luckyNumbers)
let second_result = second(first_result)
let third_result = third(second_result)
for result in third_result {
print(result)
}
}
doImportantWorkChain { number in
return number.filter {
return $0.isMultiple(of: 2)
}
} second: { number in
return number.sorted {
return $0 < $1
}
} third: { number in
return number.map {
("\($0) is the lucky number")
}
}
I am playing around with the custom operator >>> for function composition that is suggested here.
I have defined the following:
infix operator >>> { associativity left }
func >>> <A, B, C>(f: B -> C, g: A -> B) -> (A -> C) {
return { x in f(g(x)) }
}
func toChars(s: String) -> [Character] {
return s.characters.reduce([]) { (acc, c) in acc + [c] }
}
func myReverse(xs: [Character]) -> String {
if let (head, tail) = xs.decompose {
return String(myReverse(tail)) + String(head)
}
return ""
}
Now, when I want to put together those two functions like this:
func reverseString(s: String) -> String {
return myReverse >>> toChars
}
I am getting the compiler error:
Cannot convert value of type ([Character]) -> String to expected
argument type _ -> _.
According to my understanding this should work. >>> is defined to take two functions f : B -> C and g : A -> B. Looking at the structure of my usage, the following becomes clear:
g in this case is toChar : String -> [Character], so A is String and B is [Character]
f in this case is myReverse : [Character] -> String, so B is [Character] and C is String
This matches the type definitions form above, however I am still getting a compiler error. Does anyone know what I am doing wrong? Is there a syntax issue with the code?
Note, I am using an Array extension where the function decompose is defined like so:
var decompose : (head: Element, tail: [Element])? {
if count > 0 {
return (self[0], Array(self[1..<count]))
}
return nil
}
myReverse >>> toChars returns a closure of type String -> String,
you still have to call the closure with a string argument:
func reverseString(s: String) -> String {
return (myReverse >>> toChars)(s)
}
But what you probably want is:
let reverseString = myReverse >>> toChars
In both cases, reverseString has the type String -> String,
so you can call it as
print(reverseString("foo"))
// oof
am studying with a tutorial for a game app and there is a line of code that i didn't understood it looks like it's of type tuple
this is my code:
var algorithmResult = algorithm(value: value)
func rowCheck(#value: Int) -> (location: String, pattern: String)? {
var acceptableFinds = ["011", "101", "110"]
var findFunc = [checkTop, checkBottom, checkMiddleAcross, checkRight, checkMiddleDown, checkLeft, checkDiagLeftRight, checkDiagRightLeft]
for algorithm in findFunc {
var algorithmResult = algorithm(value: value)
if (find(acceptableFinds, algorithmResult.pattern) != nil) {
return algorithmResult
}
}
return nil
}
In:
var algorithmResult = algorithm(value: value)
algorithm represents one element in the findFunc array (as defined in for algorithm in findFunc).
From the names, I'm guessing each of those elements is a function. Those functions are passed value and the result of the function is stored in algorithmResult.
Here's a similar example. Create two functions:
func add(operand : Int) -> Int {
return operand + operand
}
func multiply(operand : Int) -> Int {
return operand * operand
}
Store them in an array:
let funcs = [add, multiply]
Call them in a loop:
for function in funcs {
let x = function(5)
print(x)
}
This prints:
10
25
It applies each function from findFunc array to the value, which was passed to rowCheck function.
Lets say I have an Array of String and I want to map it to an Array of Int
I can use the map function:
var arrayOfStrings: Array = ["0", "a"]
let numbersOptional = arrayOfStrings.map { $0.toInt() }
// numbersOptional = "[Optional(0), nil]"
Numbers is now an Array of Int?, but I want an Array of Int.
I know I can do this:
let numbers = arrayOfStrings.map { $0.toInt() }.filter { $0 != nil }.map { $0! }
// numbers = [0]
But that doesn't seem very swift. Converting from the Array of Int? to Array of Int requires calling both filter and map with pretty much boilerplate stuff. Is there a more swift way to do this?
Update: As of Swift 1.2, there's a built-in flatMap method for arrays, but it doesn't accept Optionals, so the helper below is still useful.
I like using a helper flatMap function for that sort of things, just like Scala's flatMap method on collections (which can consider an Scala Option as a collection of either 0 or 1 element, roughly spoken):
func flatMap<C : CollectionType, T>(source: C, transform: (C.Generator.Element) -> T?) -> [T] {
var buffer = [T]()
for elem in source {
if let mappedElem = transform(elem) {
buffer.append(mappedElem)
}
}
return buffer
}
let a = ["0", "a", "42"]
let b0 = map(a, { $0.toInt() }) // [Int?] - [{Some 0}, nil, {Some 42}]
let b1 = flatMap(a, { $0.toInt() }) // [Int] - [0, 42]
This definition of flatMap is rather a special case for Optional of what a more general flatMap should do:
func flatMap<C : CollectionType, T : CollectionType>(source: C, transform: (C.Generator.Element) -> T) -> [T.Generator.Element] {
var buffer = [T.Generator.Element]()
for elem in source {
buffer.extend(transform(elem))
}
return buffer
}
where we'd get
let b2 = flatMap(a, { [$0, $0, $0] }) // [String] - ["0", "0", "0", "a", "a", "a", "42", "42", "42"]
Using reduce to build the new array might be more idiomatic
func filterInt(a: Array<String>) -> Array<Int> {
return a.reduce(Array<Int>()) {
var a = $0
if let x = $1.toInt() {
a.append(x)
}
return a
}
}
Example
filterInt(["0", "a", "42"]) // [0, 42]
What you would really want is a collect (map + filter) method. Given the specific filter you need to apply, in this case even a flatMap would work (see Jean-Philippe's answer). Too bad both methods are not provided by the swift standard library.
update: Xcode 7.2 • Swift 2.1.1
let arrayOfStrings = ["0", "a", "1"]
let numbersOnly = arrayOfStrings.flatMap { Int($0) }
print(numbersOnly) // [0,1]
There’s no good builtin Swift standard library way to do this. However, Haskell has a function, mapMaybe, that does what you’re looking for (assuming you just want to ditch nil values). Here’s an equivalent in Swift:
func mapSome<S: SequenceType, D: ExtensibleCollectionType>
(source: S, transform: (S.Generator.Element)->D.Generator.Element?)
-> D {
var result = D()
for x in source {
if let y = transform(x) {
result.append(y)
}
}
return result
}
// version that defaults to returning an array if unspecified
func mapSome<S: SequenceType, T>
(source: S, transform: (S.Generator.Element)->T?) -> [T] {
return mapSome(source, transform)
}
let s = ["1","2","elephant"]
mapSome(s) { $0.toInt() } // [1,2]
You can consider using reduce, it's more flexible:
var arrayOfStrings: Array = ["0", "a"]
let numbersOptional = arrayOfStrings.reduce([Int]()) { acc, str in
if let i = str.toInt() {
return acc + [i]
}
return acc
}
The declaration of indexesOfObjectsPassingTest: looks like this in Swift,
func indexesOfObjectsPassingTest(predicate: ((AnyObject!, Int, CMutablePointer<ObjCBool>) -> Bool)!) -> NSIndexSet!
I've tried all sorts of permutations to get this to work, but I'm stumped, particularly with how you deal with this piece, CMutablePointer<ObjCBool>) -> Bool)!. I found it confusing enough, when I was first learning blocks in objective-c, how you translate from the declaration to actual use of a method, and the syntax of Swift is at least as confusing.
This code is working in the Playground for me ;) Hope it helps a bit
Extra Function-Definition
import Cocoa
let list = [2, 3, 4, 5, 6, 7, 8]
func test (object: AnyObject!, index: Int, stop: CMutablePointer<ObjCBool>) -> Bool
{
let number = object as Int
return (number % 2 == 0) //for even numbers
}
let result: NSIndexSet = (list as NSArray).indexesOfObjectsPassingTest(test)
println("\(result.lastIndex)") //prints "6" (because 8%2=0)
Inline-Closure
I transformed my above example to work with an inline-closure (described in the Swift-eBook). The parameter-list and return-type is separated by the term in.
import Cocoa
let list = [2, 3, 4, 5, 6, 7, 8]
let result: NSIndexSet = (list as NSArray).indexesOfObjectsPassingTest({
(object: AnyObject!, index: Int, stop: CMutablePointer<ObjCBool>) -> Bool in
let number = object as Int
return (number % 2 == 0) //for even numbers
})
println("\(result.lastIndex)") //prints "6" (because 8%2=0)
Seems like CMutablePointer was recently changed to UnsafeMutablePointer.
This one worked for me:
let indices = myArray.indexesOfObjectsPassingTest({
(obj: AnyObject!, idx: Int, stop: UnsafeMutablePointer<ObjCBool>) -> Bool in
var didPass = false
//determine if obj passes test, if it does set didPass = true
return didPass
})
The block syntax is being replaced in Swift by a closure, the predicate parameter here.
So you can just do:
var array = NSArray(array: [1, 2, 3, 4, 5])
var indexSet = array.indexesOfObjectsPassingTest({ (val: AnyObject!, index: Int, stop: CMutablePointer<ObjCBool>) -> Bool in return index > 2 })
indexSet.count
Out of the method, it could look like this:
var closure = {(val: AnyObject!, index: Int, stop: CMutablePointer<ObjCBool>) -> Bool? in
/* Do Something */
}
Hope this helps.