Recursion Over a Swift Sliceable

Recursion over a Swift Sliceable

It turns out that there is a generic solution. You need to add these generic requirements:

<  
S : Sliceable where S.SubSlice : Sliceable,
S.SubSlice.Generator.Element == S.Generator.Element,
S.SubSlice.SubSlice == S.SubSlice
>

For the question posted, this gives:

func recurseSeq<
S : Sliceable where S.SubSlice : Sliceable,
S.SubSlice.Generator.Element == Int,
S.SubSlice.SubSlice == S.SubSlice,
S.Generator.Element == Int
>(list: S) -> [Int] {

guard let first = list.first else {
return []
}

let rest = recurseSeq(dropFirst(list))
let next = rest.first ?? 0

return [first + next] + rest
}

Here's a useful generic reduce on any sliceable:

extension Sliceable where  
SubSlice : Sliceable,
SubSlice.Generator.Element == Generator.Element,
SubSlice.SubSlice == SubSlice {

func recReduce(combine: (Generator.Element, Generator.Element) -> Generator.Element) -> Generator.Element? {

return self.first.map {
head in
dropFirst(self)
.recReduce(combine)
.map {combine(head, $0)}
?? head
}
}
}
[1, 2, 3].recReduce(+) // 6

I can't take credit for this, the solution was posted on the Apple Development Forums.

It's a shame that the generic requirements are so involved for such a a basic operation - it's hardly intuitive! But I'm glad to have a solution...

Unify Arrays and Array Slices in Swift

Yeah, the Array/ArraySlice thing is annoying. The basic generic requirements you need are detailed in this question. To get your requirements, though, unfortunately you've got to get some pretty hideous function signatures. It is possible, though:

func bSearch<
S : Sliceable where S.SubSlice : Sliceable,
S.SubSlice.Generator.Element == S.Generator.Element,
S.SubSlice.SubSlice == S.SubSlice,
S.Generator.Element : Comparable,
S.Index : IntegerArithmeticType,
S.Index : IntegerLiteralConvertible,
S.SubSlice.Index == S.Index
>(el: S.Generator.Element, list: S) -> S.Generator.Element? {

if list.isEmpty { return nil }

let midInd = list.endIndex / 2

let midEl: S.Generator.Element = list[midInd] // type inference giving me some bugs here

if midEl == el {
return el
}

return midEl < el ?
bSearch(el, list: list[midInd+1..<list.endIndex]) :
bSearch(el, list: list[0..<midInd])
}

And for Swift 1.2, just swap out the body for this:

if isEmpty(list) { return nil }

let midInd = list.endIndex / 2

let midEl: S.Generator.Element = list[midInd] // type inference giving me some bugs here

if midEl == el {
return el
}

return midEl < el ?
bSearch(el, list[midInd+1..<list.endIndex]) :
bSearch(el, list[0..<midInd])

Filter, Closure, Functional syntax version of for loop with multiple conditions

If you want the first element of the array that satisfies the criteria
use this.

if let voiceToUse = AVSpeechSynthesisVoice.speechVoices().first(where: {
$0.name == "Samantha (Enhanced)" && $0.quality == .enhanced
}){

//use the voiceTouse Variable

}

If you want the last of the element of the array that satisfies the
criteria use this.

if let voiceToUse = AVSpeechSynthesisVoice.speechVoices().reversed().first(where: {
$0.name == "Samantha (Enhanced)" && $0.quality == .enhanced
}){

//use the voiceTouse Variable

}

yes sure, we can use guard let ...

A guard statement is used to transfer program control out of a scope if one or more conditions aren’t met.
in this example, if the condition is not met, ie there is no element in AVSpeechSynthesisVoice.speechVoices() that meet the criteria, guard let will transfer the program control out of the check function ,else if there is the some element in AVSpeechSynthesisVoice.speechVoices() that meet the criteria, program control goes to the next line after the guard let statement

func check(){
guard let voiceToUse = AVSpeechSynthesisVoice.speechVoices().first(where: {
$0.name == "Samantha (Enhanced)" && $0.quality == .enhanced
})else{
return
}
//use the voiceToUseVariable

}

check()


Related Topics



Leave a reply



Submit