How to Build a Recursive Function in Swift to Return a String

How can I build a recursive function in Swift to return a String?

Here you go:

func desc(_ s:String? = nil) -> String {
var me = String(describing:self.value)
if let prev = s {
me += "/" + prev
}
return self.parent?.desc(me) ?? me
}

Example:

let n = Node("hey")
n.add(Node("ho"))
n.children.first?.add(Node("nonny nonny no"))
let start = n.children.first!.children.first!
print(start.desc())

Swift: Returning a recursive function (currying)

I ended up solving it with something like the following, what it does is create a class reference to store the next function in. I pass a reference to this object in the completion of the asynchronous operation.

extension Product {
class Next {

typealias FunctionType = (([Product], Next) -> Void) -> Task?
let fetch: FunctionType

init(_ fetch: FunctionType) {
self.fetch = fetch
}

}

func fetch(dataGateway: DataGateway, inCategory category: String)(page: UInt)(completion: ([Product], Next) -> Void) -> Task? {

return dataGateway.products(inCategory: category, page: page)() { products in
completion(products.map { $0.build }, Next(fetch(dataGateway, inCategory: category)(page: page + 1)))
}

}
}

let initial = Product.fetch(dataGateway, inCategory: "1")(page: 0)

pass the function in to a data model

data() { [weak self] products, next in 
self?.data = products
self?.setNeedsUpdate()
self?.next = next
}

scrolling down to bottom of table view triggers the above again, using the next function instead of data

Writing a Swift function that returns itself

Let's try to write such a thing.

func f() {
return f
}

Now the compiler complains because f is not declared to return anything when it does return something.

Okay, let's try to add a return value type i.e. A closure that accepts no parameters and return nothing.

func f() -> (() -> ()) {
return f
}

Now the compiler complains that f is () -> (() -> ()), and so cannot be converted to () -> ().

We should edit the declaration to return a () -> (() -> ()), right?

func f() -> (() -> (() -> ())) {
return f
}

Now f becomes a () -> (() -> (() -> ())), which cannot be converted to a () -> (() -> ())!

See the pattern now? This will continue forever.

Therefore, you can only do this in a type-unsafe way, returning Any:

func f() -> Any { return f }

Usage:

func f() -> Any {
print("Hello")
return f
}
(f() as! (() -> Any))()

The reason why this is possible in python is exactly because Python is weakly typed and you don't need to specify the return type.

Note that I do not encourage you to write this kind of code in Swift. When you code in Swift, try to solve the problem with a Swift mindset. In other words, you should think of another way of solving the problem that does not involve a function like this.

Is there a way to end a recursive method when a certain condition is met in Swift?

When using recursive function you should return value on both condition

 func getLength(value: Int, font: UIFont, viewFrame: CGRect) -> (width:CGFloat, text:String) {
let width: CGFloat!
var val = value

let size = String(format:"%d",value).size(attributes: [NSFontAttributeName: font])
if size.width+10 > viewFrame.size.width {
width = viewFrame.size.width-10
val = val/10
return getLength(value: val, font: font, viewFrame: viewFrame)

} else {
width = size.width+10
return (width,String(format:"%d+",val))
}
}

How to write this recursive function in Swift?

With thanks to sunshine for finding 1 -> i. I got a different result and thought I messed up the algorithm.


No need for your Array extension, but it would be correctly written like so:

extension Array {
func concat(toAdd: [Element]) -> [Element] {
return self + toAdd
}
func concat(toAdd: Element) -> [Element] {
return self + [toAdd]
}
}

No need for Any at all. The type is always known.

for spacing in 0...maxSpacing for subSpacing in subSpacings Swiftier syntax for iterations.

func permutateSpacings(columns: Int, maxSpacing: Int) -> [[Int]] {
if columns == 1 {
return [[maxSpacing]]
}

var results : [[Int]] = [] // var/let : Type = Value

for spacing in 0...maxSpacing {
let subSpacings = permutateSpacings(columns - 1, maxSpacing: maxSpacing - spacing)
for subSpacing in subSpacings {
results.append(([spacing] + subSpacing))
}
}
return results
}

How can you leverage Swift features to refactor this recursive function?

Instead of recursion, you can use reduce on the keys array
to traverse through the dictionary:

func extractFromNestedDictionary(dictionary: NSDictionary, withKeys keys: [String]) -> String? {

return reduce(keys, dictionary as AnyObject?) {
($0 as? NSDictionary)?[$1]
} as? String
}

Inside the closure, $0 is the (optional) object on the current level and $1
the current key. The closure returns the object on the next level
if $0 is a dictionary and has a value for the current key,
and nil otherwise. The return value from reduce() is then
the object on the last level or nil.

Build Recursive Text View in SwiftUI

There are a few things to clarify here:

The + overload of Text only works between Texts which is why it's saying it cannot convert some View (your return type) to Text. Text + Text == Text, Text + some View == ☠️

Changing the return type to Text doesn't work for you because you're using @ViewBuilder, remove @ViewBuilder and it'll work fine.

Why? @ViewBuilder allows SwiftUI to defer evaluation of the closure until later but ensures it'll result in a specific view type (not AnyView). In the case where your closure returns either a Text or an Image this is handy but in your case where it always results in Text there's no need, @ViewBuilder forces the return type to be ConditionalContent<Text, Text> so that it could have different types.

Here's what should work:

private static func attributedTextView(text: String) -> Text {
if let range = text.range(of: "[0-9]+d[0-9]+", options: .regularExpression) {

//The unattributed text
return Text(text[text.startIndex..<range.lowerBound]) +

//Append the attributed text
Text(text[range]).bold() +

//Search for additional instances of text that needs attribution
AttributedTextView(text: String(text[range.upperBound..<text.endIndex]))

} else {
//If the searched text is not found, add the rest of the string to the end
return Text(text)
}
}

I made it static too because there's no state here it's a pure function and lowercased it so it was clear it was a function not a type (the function name looks like a View type).

You'd just call it Self.attributedTextView(text: ...)

Recursive Block in Swift

Here’s a straight translation of your obj-c version:

func recursiveBlockVehicle(block: @escaping (()->Void)->Void) -> ()->Void {
return { block(recursiveBlockVehicle(block: block)) }
}

// test usage
var i = 5
let block = recursiveBlockVehicle { recurse in
if i > 0 {
print("\(i--) ")
recurse()
}
else {
println("blastoff!")
}
}

block() // prints 5 4 3 2 1 blastoff!

(I’ve subbed out the dispatch_block_t since it doesn’t feel necessary in the Swift version, but you can use it instead of ()->Void instead if you prefer)

For the 1-parameter version, you can use generics rather than the obj-c id approach, so it can create type-safe single-parameter recursive blocks:

func recursiveBlockVehicle<T>(block: @escaping (T, (T)->Void)->Void) -> (T)->Void {
return { param in block(param, recursiveBlockVehicle(block: block)) }
}

let block1: (Int)->Void = recursiveBlockVehicle { i, recurse in
if i > 0 {
print("\(i) ")
recurse(i-1)
}
else {
print("blastoff!")
}
}

block1(5) // prints 5 4 3 2 1 blastoff!

(and Swift overloading means you don’t have to give them different names)

...and if you want your recursive function to return a value:

func recursiveBlockVehicle<T,U>(block: @escaping (T, (T)->U)->U) -> (T)->U {
return { (param: T)->U in block(param, recursiveBlockVehicle(block: block)) }
}

let factorial: (Int)->Int = recursiveBlockVehicle { i, factorial in
return i > 1 ? i*factorial(i-1) : 1
}

factorial(4) // returns 24

Note, this last one is really the only one you need – since T and U can be Void, it serves the purposes of the zero-parameter non-returning one too, though you have to write your closures to take two parameters (the first one of which you can ignore, since it’ll be void), i.e.:

let block: ()->() = recursiveBlockVehicle { _, recurse in

If you like this sort of stuff you should check out the 2014 WWDC Advanced Swift video which as an example of a memoizing recursive function caller.

Calculate the data received inside the recursive function

You do not need a global variable. There are at least two other options. You can add an inout parameter to allLexicographicRecur to keep track of the count or you can have allLexicographicRecur return its count.

Here's your code using a return value:

func allLexicographicRecur(_ string: [String.Element], _ data: [String], _ last: Int, _ index: Int) -> Int {
let length = string.count - 1
var data = data
var count = 0
for i in 0...length {
data[index] = String(string[i])
if index == last {
print(data.joined()) // Displays a combination. It is necessary to somehow calculate.
count += 1
} else {
count += allLexicographicRecur(string, data, last, index + 1)
}
}

return count
}

func allLexicographic(_ l: Int) -> Int {
let alphabet = "abc"
let data = Array(repeating: "", count: l)
let string = alphabet.sorted()
return allLexicographicRecur(string, data, l - 1, 0)
}

print(allLexicographic(3))

Here's your code updated to use an inout parameter.

func allLexicographicRecur(_ string: [String.Element], _ data: [String], _ last: Int, _ index: Int, _ count: inout Int){
let length = string.count - 1
var data = data
for i in 0...length {
data[index] = String(string[i])
if index == last {
print(data.joined()) // Displays a combination. It is necessary to somehow calculate.
count += 1
} else {
allLexicographicRecur(string, data, last, index + 1, &count)
}
}
}

func allLexicographic(_ l: Int) -> Int {
let alphabet = "abc"
let data = Array(repeating: "", count: l)
let string = alphabet.sorted()
var counter = 0
allLexicographicRecur(string, data, l - 1, 0, &counter)
return counter
}

print(allLexicographic(3))


Related Topics



Leave a reply



Submit