How can I chain functions when i call it in Swift? - ios

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

Related

Find lowest value and its index number in swift

I have the following array
var numbers = [2, 4, 4, 2, 3, 1]
The sequence is very important and I need to find the index of the lowest value.
So how can I find the lowest value index? I need to be able to call numbers[lowestValueIndex] and get the correct value
Any help is appreciated
I always think it gives a cleaner call site to extend the array in this type of scenario.
extension Array where Element == Int {
func lowest() -> (value: Element, positions:[Index])? {
guard !isEmpty else {return nil } //you may wish to throw an error rather than return nil
return indices.reduce( (value: Element.max, positions: [Index]() ) ) {
switch self[$1] {
case let x where x < $0.value: return (value: self[$1], positions:[$1])
case let x where x > $0.value: return $0
default: return ($0.value, $0.positions + [$1])
}
}
}
}
The switch statements can be simplified using an _ or pattern matching, but I feel this more verbose approach is easier to understand. Throwing an error or returning a Result may be nicer way of dealing with an empty array than an optional return type, but would add bloat to the answer and can be added later by the OP if preferred.
[2,3,6,1,7,3,1,6,7].lowest() // (value: 1, positions: [3, 6])
[2,3,6,6,7,3,1,6,7].lowest() // (value: 1, positions: [6])
[Int]().lowest() // nil
You can use the min(by:) array method; The trick is to operate on the array's indices property so that you can return the relevant index:
func minIndex(someArray: [Int]) -> Int? {
return someArray.indices.min { someArray[$0] < someArray[$1] }
}
The function will return nil in the case where the array is empty.
For simplicity I have shown this as a function. You could, of course, implement this as an extension on Array if you desired.
The other answers handle what to do if you only need one value. Otherwise…
let numbers = [2, 4, 4, 2, 3, 1, 1]
// [(offset 5, element 1), (offset 6, element 1)]
numbers.min().map { min in
numbers.enumerated().filter { $0.element == min }
}
And if you're going to need the array sorted for further usage, prefix is better than filter.
let sorted =
[2, 4, 4, 2, 3, 1, 1]
.enumerated()
.sorted(by: \.element)
sorted.first.map { first in
sorted.prefix { $0.element == first.element }
}
public extension Sequence {
/// Sorted by a common `Comparable` value.
func sorted<Comparable: Swift.Comparable>(
by comparable: (Element) throws -> Comparable
) rethrows -> [Element] {
try sorted(by: comparable, <)
}
/// Sorted by a common `Comparable` value, and sorting closure.
func sorted<Comparable: Swift.Comparable>(
by comparable: (Element) throws -> Comparable,
_ areInIncreasingOrder: (Comparable, Comparable) throws -> Bool
) rethrows -> [Element] {
try sorted {
try areInIncreasingOrder(comparable($0), comparable($1))
}
}
}
First you need to define the behavior of repetitive value in the input array.
Once that is done, try this:
func returnLowestValueIndex(array: [Int]) -> Int? {
guard !array.isEmpty else { return nil }
var lowestValueIndex: Int = 0
for (index, value) in array.enumerated() {
if value < array[lowestValueIndex] {
lowestValueIndex = index
}
return lowestValueIndex
}
var numbers = [2, 4, 4, 2, 3, 10]
returnLowestValueIndex(array: numbers)

Using higher order functions in swift

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"]

Swift Filtering array elements

I am creating a function that will filter an array, e.g.
x = [10,20,30,40,50]
filter(x,10,20)
output should be 30,40,50.
I am getting an index out of bounds error .
Here's my code:
func filterArray( _ x: [Int], _ nums: Int...) -> [Int]{
var arrayX = x
for i in 0...arrayX.count-1{
for j in 0...nums.count-1 {
if arrayX[i] == nums[j]{//Changed arrayX to x because x was never changed
if let index = arrayX.index(of: nums[j]) {
arrayX.remove(at: index) //error is here
}
else{
}
}
}
}
return arrayX
}
var mArray = [10,20,30,40,50]
filterArray(mArray,10)
The way you are doing it is not correct, you are altering an array while looping through it. When you remove an object from the array, the array count changes but the loop still run using the previously calculated array.count value.
There is a much simpler way of doing this, you just need to combine filter and contains functions together for achieving this:
func filterArray( _ x: [Int], _ nums: Int...) -> [Int]
{
let filteredArray = x.filter({ !nums.contains($0)})
return filteredArray
}
once you remove one element from array its size change, but your loop is still going till previous count that is causing the issue try taking different array to go through the loop and for storing the result and you don't need to find the index its already there, value of 'i' is the index of the element.
You function can be faster if you use a Set.
func filter(list: [Int], _ remove: Int...) -> [Int] {
let removeSet = Set(remove)
return list.filter { removeSet.contains($0) }
}

Swift Array diff

Given two arrays, where one is the old set of values and the other is the new values, I want to find the "diff" of those two arrays such updates to the original array can be represented as:
enum CollectionChange<T: SequenceType> {
case Initial(T)
case Update(T, deletions: [Int], insertions: [Int], modifications: [Int])
}
I'm trying to build a simpler version of this where the changes object is built based on object equality, instead of indexes as RAC-MutableCollectionProperty is (for which the code is here and what might be the most complicated bit of code I've seen in a while; no documentation doesn't help).
Also important for this project is the ability to be able to observe changes to an array at any level of granularity. For example, a one-dimensional array, restricting T to Equatable, is a relatively easy use case. You can, as RAC-MutableCollectionProperty build up some sort of table that describes the changes, checking for equality on the objects. However once you get down to using two-dimensional arrays and deeper it gets a bit trickier because not only do you have to diff the elements at the lowest level but also describe section-level removals. In practice, no more than 2D arrays is really ever necessary but it'd be nice to have a solution that works regardless of the array depth. I'm not necessarily looking for a solution (although that'd be fantastic), really just any pointers and high level solutions on how to approach this problem.
One way I've thought of to observe multiple array levels is to write a diffing function that works on single dimensional arrays and construct a property such that:
let property: MutableCollectionProperty<MutableCollectionProperty<Int>>
where the property would check if its generic type is of it's own type. I'd have to change the changes description to something closer to
enum Changes<T> {
case Initial(T)
case Update(T, deletions: [NSIndexPath], insertions: [NSIndexPath], modifications: [NSIndexPath])
}
or maybe something like
enum Changes<T> {
case Initial(T)
case UpdateSections(sections: [T], deletions:[Int], insertions: [Int], modifications: [Int])
case UpdateIndexes(T, deletions: [Int], insertions: [Int], modifications: [Int])
}
These are just my preliminary thoughts though, I'm open to any solution or suggestion.
BOUNTY EDIT:
The bounty will be awarded to someone who can provide a solution that given the following parameters:
Let x and y be two swift array
both arrays of type T: Equatable
both arrays can be of any depth
the depth of x == the depth of y
a change set can be generated where a change set describes:
which elements have been deleted from the x
to y (by index)
which elements have been inserted into y that
weren't in x (by index)
which elements have been moved going from x
to y (by index)
Changes only have to be described at the lowest level of the array (no need to worry about insertion & removal of higher segments, although you'd really earn the 300 rep with that) but change indexes must indicate the nested index path.
For example, if the array is a 3d array and an object at array[0][5][2] was deleted, the resulting index change should be an array [0, 5, 2]. That array describes a single deletion and all the deletions would be of type [[Int]].
Edit:
I'm removing the requirement of the arrays being of any depth. Let's say that they're simply 1d arrays.
I'm not sure this meets all your bounty requirements, but I'll post some code I use for computing arrays differences:
func arrayInsertionDeletionAndNoopIndexes<T: Equatable>(objects: [T], originalObjects: [T]) -> ([Int], [Int], [Int]) {
let insertions = objects.filter({ !originalObjects.contains($0) }).map({ objects.index(of: $0)! })
let noops = originalObjects.filter({ objects.contains($0) }).map({ originalObjects.index(of: $0)! })
let deletions = originalObjects.filter({ !objects.contains($0) }).map({ originalObjects.index(of: $0)! })
return (insertions, deletions, noops)
}
func arrayInsertionDeletionAndNoopIndexPaths<T: Equatable>(objects: [T], originalObjects: [T], section: Int = 0) -> ([IndexPath], [IndexPath], [IndexPath]) {
let (insertions, deletions, noops) = arrayInsertionDeletionAndNoopIndexes(objects: objects, originalObjects: originalObjects)
let insertionIndexPaths = insertions.map({ IndexPath(row: $0, section: section) })
let deletionIndexPaths = deletions.map({ IndexPath(row: $0, section: section) })
let noopIndexPaths = noops.map({ IndexPath(row: $0, section: section) })
return (insertionIndexPaths, deletionIndexPaths, noopIndexPaths)
}
My specific use case is for computing differences to update a UITableView, for which purpose I also have the following:
extension UITableView {
func insertAndDeleteCellsForObjects<T: Equatable>(objects: [T], originalObjects: [T], section: Int = 0) {
let (insertions, deletions, _) = arrayInsertionDeletionAndNoopIndexPaths(objects: objects, originalObjects: originalObjects, section: section)
if insertions.count > 0 || deletions.count > 0 {
beginUpdates()
insertRows(at: insertions, with: .automatic)
deleteRows(at: deletions, with: .automatic)
endUpdates()
}
}
}
As of Swift 2.2, this is impossible.
You give the following requirements:
both arrays of type T: Equatable
both arrays can be of any depth
But the ability to make a constrained extension conform to a new protocol is only planned for Swift 3.0, so right now you can't make extension Array where Element: Array<Equatable> conform to Equatable protocol. This means that only 1d arrays can be of of type T: Equatable.
EDIT:
Basically what you need to do is to write an algorithm that solves Longest common subsequence problem. For 1d arrays you can use Dwifft library which solves the problem in the following way:
public extension Array where Element: Equatable {
public func diff(other: [Element]) -> Diff<Element> {
let table = MemoizedSequenceComparison.buildTable(self, other, self.count, other.count)
return Array.diffFromIndices(table, self, other, self.count, other.count)
}
private static func diffFromIndices(table: [[Int]], _ x: [Element], _ y: [Element], _ i: Int, _ j: Int) -> Diff<Element> {
if i == 0 && j == 0 {
return Diff<Element>(results: [])
} else if i == 0 {
return diffFromIndices(table, x, y, i, j-1) + DiffStep.Insert(j-1, y[j-1])
} else if j == 0 {
return diffFromIndices(table, x, y, i - 1, j) + DiffStep.Delete(i-1, x[i-1])
} else if table[i][j] == table[i][j-1] {
return diffFromIndices(table, x, y, i, j-1) + DiffStep.Insert(j-1, y[j-1])
} else if table[i][j] == table[i-1][j] {
return diffFromIndices(table, x, y, i - 1, j) + DiffStep.Delete(i-1, x[i-1])
} else {
return diffFromIndices(table, x, y, i-1, j-1)
}
}
}
internal struct MemoizedSequenceComparison<T: Equatable> {
static func buildTable(x: [T], _ y: [T], _ n: Int, _ m: Int) -> [[Int]] {
var table = Array(count: n + 1, repeatedValue: Array(count: m + 1, repeatedValue: 0))
for i in 0...n {
for j in 0...m {
if (i == 0 || j == 0) {
table[i][j] = 0
}
else if x[i-1] == y[j-1] {
table[i][j] = table[i-1][j-1] + 1
} else {
table[i][j] = max(table[i-1][j], table[i][j-1])
}
}
}
return table
}
}
If you only need to compute the difference between two arrays, here's an alternative implementation based on shawkinaw answer:
typealias Insertions = [Int]
typealias Deletions = [Int]
typealias ChangeSet = (Insertions, Deletions)
func Diff<T: Equatable>(objects: [T], originalObjects: [T]) -> ChangeSet {
guard objects.count > 0 && originalObjects.count > 0 else { return ChangeSet([], []) }
let insertedObjects = objects.filter({ !originalObjects.contains($0) })
let insertionIndicies = insertedObjects.compactMap({ objects.index(of: $0) })
let deletedObjects = originalObjects.filter({ !objects.contains($0) })
let deletionIndicies = deletedObjects.compactMap({ originalObjects.index(of: $0) })
return ChangeSet(insertionIndicies, deletionIndicies)
}
The insertionIndicies is an array of type Int. Each Int in the array refers to the indicies where the originalObjects array need to insert items from the objects array.
The deletionIndicies is an array of type Int. Each Int in the array refers to the indicies where the originalObjects array has to delete items.

Use logical operator as combine closure in reduce

I am trying to reduce an array of Bools by applying the logical operator OR (||) using the following code, however I get an error:
func reduceBools(values: [Bool]) -> Bool {
return values.reduce(false, combine: ||)
}
Ambiguous reference to member '||'
Analogously for integers the code works like a charm.
func reduceInts(values: [Int]) -> Int {
return values.reduce(0, combine: +)
}
I was able to make it work by adding a || function (code below) or using a { $0 || $1 } closure but I dislike these approaches and I would prefer simply passing the operator.
func ||(lhs: Bool, rhs: Bool) -> Bool {
return lhs || rhs
}
The same thing happens for the logical AND (&&) operator.
How can I make it work without using the hack above?
As an alternative, you could use the following approach
// ||
func reduceBoolsOr(values: [Bool]) -> Bool {
return values.contains(true)
}
// &&
func reduceBoolsAnd(values: [Bool]) -> Bool {
return !values.contains(false)
}
Note that .reduce comes with an overhead. If the end result is the importance of your question (rather than enquiring above the unexpected behaviour of || and && operators in this context), then perhaps the pragmatic approach above can be of help, even if it doesn't really reduce the array, however producing the same result due to the simple nature of the boolean type.
Swift 4.2+ / Xcode 10.0+
In modern versions of Swift there is allSatisfy function, which checks all elements for satisfying some rule.
In OP's case:
values.allSatisfy { $0 }
UPD:
To make this work for OR, do
!values.allSatisfy{!$0}
Thanks to Andy Weinstein
Following approach will work
values.reduce(false) { $0 || $1 }
Ambiguous reference to member '||' means, that there are more than one possible candidates, from which compiler is not able to choose. In your case those are
public func ||<T : BooleanType, U : BooleanType>(lhs: T, #autoclosure rhs: () throws -> U) rethrows -> Bool
and
public func ||<T : BooleanType>(lhs: T, #autoclosure rhs: () throws -> Bool) rethrows -> Bool
probably your 'hack' using a { $0 || $1 } is the best solutions here.
This happens because of Swifts closure semantics. It takes your arguments and applies function to them, omitting argument names.
protocol Numeric {
...
public static func +(lhs: Self, rhs: Self) -> Self
...
}
In example with Ints, you would pass (Int, Int) into a closure, and + function in Numeric protocol expects exactly two ints to sum them.
Thats why code like below works just fine
[1, 2, 3, 4].reduce(0, +)
Because you just took 2 ints, and applied function, which takes just two ints.
If you write your own function, which would take just two argument, it would work as well.
func myOwnAwesomeFunc<T: Numeric>(a: T, b: T) -> T { in
return 1 // production ready
}
[1, 2, 3, 4].reduce(0, myOwnAwesomeFunc) // prints 1
Good so far. But why can't we write
[true, false, true].reduce(false, ||) // yields Cannot invoke 'reduce'
// with an argument list of type
// '(Bool, (Bool, #autoclosure () throws -> Bool) throws -> Bool)'
That's because this operator takes bool and a closure, which returns bool. Not bool, closure!
But if it is like this, why aren't we writing true || { false }() ?
Thats because of #autoclosure, which takes care of curly braces for us.
Main question, why is it implemented this way, so we can't use Swifts awesome short-hand closure syntax with booleans? Idk
Here's another approach, I modified the reduceBools function to take the operator as a parameter -
typealias LogicalOperator = ((Bool, #autoclosure () throws -> Bool) throws -> Bool)
func reduceBools(values: [Bool], combine: LogicalOperator) -> Bool {
var started: Bool = false
return values.reduce(into: true, { (result, value) in
result = started ? try! combine(result, value) : value // obviously up to you how you'd handle the try/catch
started = true
})
}
let bools = [true, false, false, true]
let result1 = self.reduceBools(values: bools, combine: ||)
print(result1) // prints true
let result2 = self.reduceBools(values: bools, combine: &&)
print(result2) // prints false
Or it could be more useful as an extension of Sequence -
extension Sequence where Element == Bool {
func reduce(_ combine: LogicalOperator) -> Bool {
var started: Bool = false
return self.reduce(into: true, { (result, value) in
result = started ? try! combine(result, value) : value
started = true
})
}
}
print(bools.reduce(||)) // prints true

Resources