My program fails compiling, can you help me out? It seems (from this and my previous attempts) that Swift doesn't like my usage of inout arguments.
Here's my code (it implements quicksort with logarithmic memory complexity by choosing into which part to recurse):
func sort<T: Comparable>(
_ arr: inout [T],
_ start: inout Int = 0,
_ end: inout Int = 0)
{
if end == 0 { end = arr.count }
while start < end {
var i = start
let pivot = arr[i]
for j in i + 1 ..< end
{
let t = arr[j]
if t < pivot {
arr[j] = arr[i]
arr[i] = t
i += 1
}
}
if i > start {
let bounds = [start, i, i, end]
var j = 2 * i > start + end ? 2 : 0
(start, end) = (bounds[j], bounds[j + 1])
sort(&arr, &start, &end)
j = (j + 2) % 4
(start, end) = (bounds[j], bounds[j + 1])
}
else { start += 1 }
}
}
var a = [3, 1, 4, 1, 5, 9, 2, 6, 5]
sort(&a)
print(a)
And here's the output:
Swift version 5.0.1 (swift-5.0.1-RELEASE)
swiftc -o main main.swift
swift: /home/buildnode/jenkins/workspace/oss-swift-5.0-package-linux-ubuntu-18_04/swift/lib/AST/ASTContext.cpp:3186: swift::TupleTypeElt::TupleTypeElt(swift::Type, swift::Identifier, swift::ParameterTypeFlags): Assertion `!ty->is<InOutType>() && "caller did not pass a base type"' failed.
Stack dump:
0. Program arguments: /usr/bin/swift -frontend -c -primary-file main.swift -target x86_64-unknown-linux-gnu -disable-objc-interop -color-diagnostics -module-name main -o /tmp/main-c3dd3d.o
1. While type-checking statement at [main.swift:32:1 - line:32:8] RangeText="sort(&a"
2. While type-checking expression at [main.swift:32:1 - line:32:8] RangeText="sort(&a"
/usr/bin/swift[0x423d3b4]
/usr/bin/swift[0x423b13e]
/usr/bin/swift[0x423d572]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x12890)[0x7fbbee94b890]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0xc7)[0x7fbbecdaee97]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x141)[0x7fbbecdb0801]
/lib/x86_64-linux-gnu/libc.so.6(+0x3039a)[0x7fbbecda039a]
/lib/x86_64-linux-gnu/libc.so.6(+0x30412)[0x7fbbecda0412]
/usr/bin/swift[0x1758aff]
/usr/bin/swift[0x1509882]
/usr/bin/swift[0x14f9942]
/usr/bin/swift[0x150d06a]
/usr/bin/swift[0x14fbbeb]
/usr/bin/swift[0x17d3117]
/usr/bin/swift[0x14f359b]
/usr/bin/swift[0x143c618]
/usr/bin/swift[0x143c162]
/usr/bin/swift[0x14d1c9d]
/usr/bin/swift[0x14d0e17]
/usr/bin/swift[0x14d0f22]
/usr/bin/swift[0x14f0647]
/usr/bin/swift[0xd3a10a]
/usr/bin/swift[0xd38eb0]
/usr/bin/swift[0xd38511]
/usr/bin/swift[0x4beb31]
/usr/bin/swift[0x4bd7c9]
/usr/bin/swift[0x46e630]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x7fbbecd91b97]
/usr/bin/swift[0x46ca4a]
<unknown>:0: error: unable to execute command: Aborted
<unknown>:0: error: compile command failed due to signal 6 (use -v to see invocation)
compiler exit status 254
inout arguments can't have default values, as you need to provide an actual memory location for those arguments. So you'll need to create two var's for those variables:
func sort<T: Comparable>(
_ arr: inout [T],
_ start: inout Int,
_ end: inout Int)
{
...
}
var start = 0, end = 0
sort(&arr, &start, &end)
Now, if you want to be able to call the function in an easier manner, without forcing the callers to create two variables each time, and to make sure those variables are initialized with zero, you can add an overload to your sort function:
func sort<T: Comparable>(
_ arr: inout [T],
_ start: inout Int,
_ end: inout Int)
{
...
}
func sort<T: Comparable>(_ arr: inout [T]) {
var start = 0, end = 0
sort(&arr, &start, &end)
}
var a = [3, 1, 4, 1, 5, 9, 2, 6, 5]
sort(&a)
print(a)
However, you could have an even nicer and more idiomatic call site, by extending Array (or even Collection) with your sort function:
extension Array where Element: Comparable {
mutating func mySort() {
var start = 0, end = 0
Self.mySort(&self, &start, &end)
}
private static func mySort(
_ arr: inout [Element],
_ start: inout Int,
_ end: inout Int)
{
... same sorting logic
}
}
var a = [3, 1, 4, 1, 5, 9, 2, 6, 5]
a.mySort() // instead of sort(&a)
print(a)
Related
I am trying to use recursion in Swift to print out the Fibonacci sequence for a number "n" iterations. However, I keep getting the same error.
I have already tried doing it without recursion and was able to do it. However, I am now trying to do in a more complex and "computer scientisty" way by using recursion.
func fibonacciSequence (n: Int) -> [Int] {
// Consumes a number "n", which is the number of iterations to go through with the Fibonacci formula and prints such sequence.
var fibonacciArray = [Int]()
for n in 0 ... n {
if n == 0 {
fibonacciArray.append(0)
}
else if n == 1 {
fibonacciArray.append(1)
}
else {
fibonacciArray.append (fibonacciSequence(n: (n - 1)) +
fibonacciSequence(n: (n-2)))
}
}
return fibonacciArray
I expect to call the function with a number n and for the function to print out the Fibonacci sequence. Example: if n = 5, I expect the console to print 0, 1, 1, 2, 3, 5. The error I get is this: (Cannot convert value of type '[Int]' to expected argument type 'Int').
As pointed out above, the return value is causing an error when summed. A possible way (but not recursive) of fixing the code would be to simply change the else statement:
func fibonacciSequence (n: Int) -> [Int] {
// Consumes a number "n", which is the number of iterations to go through with the Fibonacci formula and prints such sequence.
var fibonacciArray = [Int]()
for n in 0 ... n {
if n == 0 {
fibonacciArray.append(0)
}
else if n == 1 {
fibonacciArray.append(1)
}
else {
fibonacciArray.append (fibonacciArray[n-1] + fibonacciArray[n-2] )
}
}
return fibonacciArray
}
A recursive solution would be the following:
func fibonacciSequence (n: Int, sumOne: Int, sumTwo: Int, counter: Int, start: Bool) {
if start {
print(0)
print(1)
}
if counter == -1 {
print(1)
}
if (counter == n - 2) {
return
}
let sum = sumOne + sumTwo
print(sum)
fibonacciSequence(n: n, sumOne: sumTwo , sumTwo: sum, counter: counter + 1, start: false)
}
fibonacciSequence(n: 8, sumOne: 0, sumTwo: 1, counter: 0, start: true)
There is probably a "nicer" way, but I hope it helps. Cheers.
These is my solution for fabonacci series in swift 5 playground
func fibonacci(n: Int) {
var num1 = 0
var num2 = 1
var nextNum = Int()
let i = 1
var array = [Int]()
array.append(num1)
array.append(num2)
for _ in i...n {
nextNum = num1 + num2
num1 = num2
num2 = nextNum
array.append(num2)
print(array)
}
print("result = \(num2)")
}
print(fibonacci(n: 5))
let fibonacci = sequence(state: (0, 1)) {(state: inout (Int, Int)) -> Int? in
defer { state = (state.1, state.0 + state.1) }
return state.0
}
//limit 10
for number in fibonacci.prefix(10) {
print(number)
}
// MARK: - Function
func fibonacciSeries(_ num1 : Int,_ num2 : Int,_ term : Int,_ termCount : Int) -> Void{
if termCount != term{
print(num1)
fibonacciSeries(num2, num2+num1, term, termCount + 1)
}
}
// MARK: - Calling Of Function fibonacciSeries(0, 1, 5, 0)
// MARK: - out Put 0 1 1 2 3
Note Need to Change only No Of term for fibonacci Series.
func fibonacci(n: Int) {
var seq: [Int] = n == 0 ? [0] : [0, 1]
var curNum = 2
while curNum < n{
seq.append(seq[curNum - 1] + seq[curNum - 2])
curNum += 1 }
print(seq) }
Recursive way of fabonacci -> Solutions
func fibo( n: Int) -> Int {
guard n > 1 else { return n }
return fibo(n: n-1) + fibo(n: n-2)
}
I'm trying to figure out the behaviour of dropLast when evaluated lazily (questions in bold):
var iterationCount = 0
let sequence = [1, 1, 1].lazy.flatMap { (element: Int) -> [Int] in
iterationCount += 1
return [element, 2]
}.dropLast()
print(iterationCount) // 18
_ = sequence.forEach{_ in}
print(iterationCount) // 30
Shouldn't the first call to print show 0 and the second call to print show 3 since it's lazy? It shows 18 and 30EXAMPLE.
var iterationCount = 0
let sequence = [1, 1, 1].lazy.flatMap { (element: Int) -> [Int] in
iterationCount += 1
return [element, 2]
}
print(iterationCount) // 0
_ = sequence.forEach{_ in}
print(iterationCount) // 3
When I remove the call to dropLast it works as expectedEXAMPLE. Is dropLast the culprit here?
var iterationCount = 0
let sequence = [1, 1, 1].lazy.map { (element: Int) -> [Int] in
iterationCount += 1
return [element, 2]
}.dropLast()
print(iterationCount) // 0
_ = sequence.forEach{_ in}
print(iterationCount) // 2
But wait, there is more. With map, dropLast works as expectedEXAMPLE.
Why is this?
The following Q&A covers a few methods of generating Fibonacci numbers in Swift, but it's quite outdated (Swift 1.2?):
Sum of Fibonacci term using Functional Swift
Question: How could we generate Fibonacci numbers neatly using modern Swift (Swift >= 3)? Preferably methods avoiding explicit recursion.
An alternative for Swift 3.0 would be to use the helper function
public func sequence<T>(first: T, while condition: #escaping (T)-> Bool, next: #escaping (T) -> T) -> UnfoldSequence<T, T> {
let nextState = { (state: inout T) -> T? in
// Return `nil` if condition is no longer satisfied:
guard condition(state) else { return nil }
// Update current value _after_ returning from this call:
defer { state = next(state) }
// Return current value:
return state
}
return sequence(state: first, next: nextState)
}
from Express for loops in swift with dynamic range:
for f in sequence(first: (0, 1), while: { $1 <= 50 }, next: { ($1, $0 + $1)}) {
print(f.1)
}
// 1 1 2 3 5 8 13 21 34
Note that in order to include zero in the resulting sequence, it
suffices to replace the initial value (0, 1) by (1, 0):
for f in sequence(first: (1, 0), while: { $1 <= 50 }, next: { ($1, $0 + $1)}) {
print(f.1)
}
// 0 1 1 2 3 5 8 13 21 34
That makes the "artificial" check
if pair.1 == 0 { pair.1 = 1; return 0 }
redundant. The underlying reason is that the Fibonacci numbers can
be generalized to negative indices (https://en.wikipedia.org/wiki/Generalizations_of_Fibonacci_numbers):
... -8, 5, -3, 2, -1, 1, 0, 1, 1, 2, 3, 5, 8, ...
Using the global sequence(state:next:) function
Swift 3.0
As one alternative we could make use of one the neat global sequence functions, a pair of functions that were implemented in Swift 3.0 (as described in evolution proposal SE-0094).
sequence(first:next:)
sequence(state:next:)
Using the latter of these, we may keep the previous and current state of the Fibonacci numbers sequence as the mutable state property in the next closure of sequence(state:next:).
func fibs(through: Int, includingZero useZero: Bool = false)
-> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: useZero ? (1, 0) : (0, 1),
next: { (pair: inout (Int, Int)) -> Int? in
guard pair.1 <= through else { return nil }
defer { pair = (pair.1, pair.0 + pair.1) }
return pair.1
})
}
// explicit type annotation of inout parameter closure
// needed due to (current) limitation in Swift's type
// inference
// alternatively, always start from one: drop useZero
// conditional at 'state' initialization
func fibs1(through: Int)
-> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: (0, 1),
next: { (pair: inout (Int, Int)) -> Int? in
guard pair.1 <= through else { return nil }
defer { pair = (pair.1, pair.0 + pair.1) }
return pair.1
})
}
Or, condensing this using tuple hacks (however executing next one extra, unnecessary, time)
func fibs(through: Int, includingZero useZero: Bool = false) -> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: useZero ? (1, 0) : (0, 1), next: {
($0.1 <= through ? $0.1 : Optional<Int>.none, $0 = ($0.1, $0.0 + $0.1)).0 })
}
func fibs1(through: Int) -> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: (0, 1), next: {
($0.1 <= through ? $0.1 : Optional<Int>.none, $0 = ($0.1, $0.0 + $0.1)).0 })
}
Note that we explicitly terminate the sequences with a nil return when the ... <= through condition is no longer met.
Example usage:
// fib numbers up through 50, excluding 0
fibs(through: 50).forEach { print($0) }
// 1 1 2 3 5 8 13 21 34
// ... or
fibs1(through: 50).forEach { print($0) }
// 1 1 2 3 5 8 13 21 34
// ... including 0
fibs(through: 50, includingZero: true).forEach { print($0) }
// 0 1 1 2 3 5 8 13 21 34
// project Euler #2: sum of even fib numbers up to 4000000
print(fibs(through: 4_000_000)
.reduce(0) { $1 % 2 == 0 ? $0 + $1 : $0 }) // 4 613 732
We could also remove the termination criteria from above to construct an infinite sequence of fibonacci numbers, to be used in combination e.g. with prefix:
func infFibs() -> UnfoldSequence<Int, (Int, Int)> {
return sequence(state: (0, 1), next: {
(pair: inout (Int, Int)) -> Int in (pair.1, pair = (pair.1, pair.0 + pair.1)).0 })
}
// prefix the first 6 fib numbers (excluding 0) from
// the infinite sequence of fib numbers
infFibs().prefix(10).forEach { print($0) }
// 1 1 2 3 5 8 13 21 34 55
Swift 3.1
When Swift 3.1 arrives, the prefix(while:) method for sequences, as described in evolution proposal SE-0045, will have been implemented. Using this additional feature, we can modify the fibs methods above to avoid the explicit by-nil conditional sequence termination:
func fibs(through: Int, startingFromZero useZero: Bool = false)
-> AnySequence<Int> {
return sequence(state: useZero ? (1, 0) : (0, 1),
next: { (pair: inout (Int, Int)) -> Int? in
defer { pair = (pair.1, pair.0 + pair.1) }
return pair.1
}).prefix(while: { $0 <= through })
}
// alternatively, always start from one: drop useZero
// conditional at 'state' initialization
func fibs1(through: Int) -> AnySequence<Int> {
return sequence(state: (0, 1),
next: { (pair: inout (Int, Int)) -> Int? in
defer { pair = (pair.1, pair.0 + pair.1) }
return pair.1
}).prefix(while: { $0 <= through })
}
Examples should work the same as for Swift 3.0 above.
In Swift 3.1, here's an iterator that generates Fibonacci numbers forever, and an infinite sequence derived from it:
class FibIterator : IteratorProtocol {
var (a, b) = (0, 1)
func next() -> Int? {
(a, b) = (b, a + b)
return a
}
}
let fibs = AnySequence{FibIterator()}
To print the first 10 Fibonacci numbers:
> print(Array(fibs.prefix(10)))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
If you want to filter or map this infinite sequence you'll need to call .lazy first, since otherwise filter or map will behave strictly and will not terminate. Here are the first 5 even Fibonacci numbers:
> print( Array(fibs.lazy.filter{$0 % 2 == 0}.prefix(5)) )
[2, 8, 34, 144, 610]
I have just saw Dhaval Gevariya code and just move print fibonacci above instead below and now it will print 0 also
func fibonaci(n: Int)
{
var fiboNumberOne = 1
var fiboNumberTwo = 0
for i in 0..<n
{
print("Fibonaci \(fiboNumberTwo)")
let temp = fiboNumberOne + fiboNumberTwo
fiboNumberOne = fiboNumberTwo
fiboNumberTwo = temp
}
}
fibonaci(n: 5)
From David kopec's book “Classic Computer Science Problems in Swift”:
By recursion
var fibMemo: [UInt: UInt] = [0: 0, 1: 1] // our old base cases
func fib3(n: UInt) > UInt
{
if let result = fibMemo[n]
{
// our new base case
return result
}
else
{
fibMemo[n] = fib3(n: n 1) + fib3(n: n 2) // memoization
}
return fibMemo[n]!
}
By iterative approach
func fib4(n: UInt) > UInt
{
if (n == 0)
{
// special case
return n
}
var last: UInt = 0, next: UInt = 1 // initially set to fib(0) & fib(1
for _ in 1..<n {
(last, next) = (next, last + next) }
return next
}
func fibonaci(n: Int)
{
var fiboNumberOne = 1
var fiboNumberTwo = 0
for i in 0..<n
{
let temp = fiboNumberOne + fiboNumberTwo
fiboNumberOne = fiboNumberTwo
fiboNumberTwo = temp
print("Fibonaci \(fiboNumberTwo)")
}
}
fibonaci(n: 5)
If you don't need accuracy there is O(1) function for your needs:
func fibonacci(iteration: Int) -> Int {
return Int(round(pow(1.618033988749895, Double(iteration)) / 2.23606797749979))
}
So here how it works:
print((0..<40).map(fibonacci))
// prints [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
Works perfectly until 70 iteration.
Warning: On 71 iteration returns 308061521170130 instead of 308061521170129
Details
Xcode 9.3.1, Swift 4.1
Solution
extension Array where Element: BinaryInteger {
private mutating func fibonacci(index: Int) {
if index >= count {
return
}
self[index] = self[index-1] + self[index-2]
return fibonacci(index: index+1)
}
init(fibonacci count: Int) {
self = [Element]()
if count < 0 {
self = [Element]()
}
self = [Element](repeating: 1, count: count)
fibonacci(index: 2)
}
static func calculate(fibonacciAt index: Int) -> Element? {
if index < 0 {
return nil
}
if index < 2 {
return 1
}
func calc(a: Element, b: Element, index: Int) -> Element {
if index == 1 {
return b
}
return calc(a: b, b: a+b, index: index-1)
}
return calc(a: 1, b: 1, index: index)
}
}
Usage
let fibonacciSequence = [Int](fibonacci: 15)
let index = 12
print(fibonacciSequence)
print(fibonacciSequence[index])
let value = [Int].calculate(fibonacciAt: index)
print("\(value!)")
Results
Details
XCode Version 10.0 beta 6, Swift 4.2
The control flow is required to get either the first or the first two iterations of the fibonacci seq starting with 0.
Time Complexity: O(n)
Space Complexity: O(n)
Code
func fib(_ n: Int) -> [Int] {
var fibs: [Int] = [0, 1]
switch n
{
case 1: return [fibs[0]]
case 2: return [fibs[0],fibs[1]]
default:
(2...n-1).forEach
{ i in
fibs.append(fibs[i - 1] + fibs[i - 2])
}
return fibs
}
}
Usage
fib(8)
//print(fib(8))
// MARK: - Function
func fibonacciSeries(_ num1 : Int,_ num2 : Int,_ term : Int,_ termCount : Int) -> Void{
if termCount != term{
print(num1)
fibonacciSeries(num2, num2+num1, term, termCount + 1)
}
}
// MARK: - Calling Of Function
fibonacciSeries(0, 1, 5, 0)
// MARK: - out Put
0 1 1 2 3
Note Need to Change only No Of term for fibonacci Series.
func fibonacci(n: Int) -> Int {
if n <= 1 {
return n
} else {
return fibonacci(n: n - 1) + fibonacci(n: n - 2)
}
}
print(fibonacci(n: 10))
This is bad to use recursion!! recursion is evil!
I would have rather done it this way:
func fibo(_ n:Int) -> Int {
var a = 0
var b = 1
for _ in 0..<n {
a += b
b = a - b
}
return a
}
Which is much faster and cleaner!
I'd like a function runningSum on an array of numbers a (or any ordered collection of addable things) that returns an array of the same length where each element i is the sum of all elements in A up to an including i.
Examples:
runningSum([1,1,1,1,1,1]) -> [1,2,3,4,5,6]
runningSum([2,2,2,2,2,2]) -> [2,4,6,8,10,12]
runningSum([1,0,1,0,1,0]) -> [1,1,2,2,3,3]
runningSum([0,1,0,1,0,1]) -> [0,1,1,2,2,3]
I can do this with a for loop, or whatever. Is there a more functional option? It's a little like a reduce, except that it builds a result array that has all the intermediate values.
Even more general would be to have a function that takes any sequence and provides a sequence that's the running total of the input sequence.
The general combinator you're looking for is often called scan, and can be defined (like all higher-order functions on lists) in terms of reduce:
extension Array {
func scan<T>(initial: T, _ f: (T, Element) -> T) -> [T] {
return self.reduce([initial], combine: { (listSoFar: [T], next: Element) -> [T] in
// because we seeded it with a non-empty
// list, it's easy to prove inductively
// that this unwrapping can't fail
let lastElement = listSoFar.last!
return listSoFar + [f(lastElement, next)]
})
}
}
(But I would suggest that that's not a very good implementation.)
This is a very useful general function, and it's a shame that it's not included in the standard library.
You can then generate your cumulative sum by specializing the starting value and operation:
let cumSum = els.scan(0, +)
And you can omit the zero-length case rather simply:
let cumSumTail = els.scan(0, +).dropFirst()
Swift 4
The general sequence case
Citing the OP:
Even more general would be to have a function that takes any sequence
and provides a sequence that's the running total of the input
sequence.
Consider some arbitrary sequence (conforming to Sequence), say
var seq = 1... // 1, 2, 3, ... (CountablePartialRangeFrom)
To create another sequence which is the (lazy) running sum over seq, you can make use of the global sequence(state:next:) function:
var runningSumSequence =
sequence(state: (sum: 0, it: seq.makeIterator())) { state -> Int? in
if let val = state.it.next() {
defer { state.sum += val }
return val + state.sum
}
else { return nil }
}
// Consume and print accumulated values less than 100
while let accumulatedSum = runningSumSequence.next(),
accumulatedSum < 100 { print(accumulatedSum) }
// 1 3 6 10 15 21 28 36 45 55 66 78 91
// Consume and print next
print(runningSumSequence.next() ?? -1) // 120
// ...
If we'd like (for the joy of it), we could condense the closure to sequence(state:next:) above somewhat:
var runningSumSequence =
sequence(state: (sum: 0, it: seq.makeIterator())) {
(state: inout (sum: Int, it: AnyIterator<Int>)) -> Int? in
state.it.next().map { (state.sum + $0, state.sum += $0).0 }
}
However, type inference tends to break (still some open bugs, perhaps?) for these single-line returns of sequence(state:next:), forcing us to explicitly specify the type of state, hence the gritty ... in in the closure.
Alternatively: custom sequence accumulator
protocol Accumulatable {
static func +(lhs: Self, rhs: Self) -> Self
}
extension Int : Accumulatable {}
struct AccumulateSequence<T: Sequence>: Sequence, IteratorProtocol
where T.Element: Accumulatable {
var iterator: T.Iterator
var accumulatedValue: T.Element?
init(_ sequence: T) {
self.iterator = sequence.makeIterator()
}
mutating func next() -> T.Element? {
if let val = iterator.next() {
if accumulatedValue == nil {
accumulatedValue = val
}
else { defer { accumulatedValue = accumulatedValue! + val } }
return accumulatedValue
}
return nil
}
}
var accumulator = AccumulateSequence(1...)
// Consume and print accumulated values less than 100
while let accumulatedSum = accumulator.next(),
accumulatedSum < 100 { print(accumulatedSum) }
// 1 3 6 10 15 21 28 36 45 55 66 78 91
The specific array case: using reduce(into:_:)
As of Swift 4, we can use reduce(into:_:) to accumulate the running sum into an array.
let runningSum = arr
.reduce(into: []) { $0.append(($0.last ?? 0) + $1) }
// [2, 4, 6, 8, 10, 12]
By using reduce(into:_:), the [Int] accumulator will not be copied in subsequent reduce iterations; citing the Language reference:
This method is preferred over reduce(_:_:) for efficiency when the
result is a copy-on-write type, for example an Array or a
Dictionary.
See also the implementation of reduce(into:_:), noting that the accumulator is provided as an inout parameter to the supplied closure.
However, each iteration will still result in an append(_:) call on the accumulator array; amortized O(1) averaged over many invocations, but still an arguably unnecessary overhead here as we know the final size of the accumulator.
Because arrays increase their allocated capacity using an exponential
strategy, appending a single element to an array is an O(1) operation
when averaged over many calls to the append(_:) method. When an array
has additional capacity and is not sharing its storage with another
instance, appending an element is O(1). When an array needs to
reallocate storage before appending or its storage is shared with
another copy, appending is O(n), where n is the length of the array.
Thus, knowing the final size of the accumulator, we could explicitly reserve such a capacity for it using reserveCapacity(_:) (as is done e.g. for the native implementation of map(_:))
let runningSum = arr
.reduce(into: [Int]()) { (sums, element) in
if let sum = sums.last {
sums.append(sum + element)
}
else {
sums.reserveCapacity(arr.count)
sums.append(element)
}
} // [2, 4, 6, 8, 10, 12]
For the joy of it, condensed:
let runningSum = arr
.reduce(into: []) {
$0.append(($0.last ?? ($0.reserveCapacity(arr.count), 0).1) + $1)
} // [2, 4, 6, 8, 10, 12]
Swift 3: Using enumerated() for subsequent calls to reduce
Another Swift 3 alternative (with an overhead ...) is using enumerated().map in combination with reduce within each element mapping:
func runningSum(_ arr: [Int]) -> [Int] {
return arr.enumerated().map { arr.prefix($0).reduce($1, +) }
} /* thanks #Hamish for improvement! */
let arr = [2, 2, 2, 2, 2, 2]
print(runningSum(arr)) // [2, 4, 6, 8, 10, 12]
The upside is you wont have to use an array as the collector in a single reduce (instead repeatedly calling reduce).
Just for fun: The running sum as a one-liner:
let arr = [1, 2, 3, 4]
let rs = arr.map({ () -> (Int) -> Int in var s = 0; return { (s += $0, s).1 } }())
print(rs) // [1, 3, 6, 10]
It does the same as the (updated) code in JAL's answer, in particular,
no intermediate arrays are generated.
The sum variable is captured in an immediately-evaluated closure returning the transformation.
If you just want it to work for Int, you can use this:
func runningSum(array: [Int]) -> [Int] {
return array.reduce([], combine: { (sums, element) in
return sums + [element + (sums.last ?? 0)]
})
}
If you want it to be generic over the element type, you have to do a lot of extra work declaring the various number types to conform to a custom protocol that provides a zero element, and (if you want it generic over both floating point and integer types) an addition operation, because Swift doesn't do that already. (A future version of Swift may fix this problem.)
Assuming an array of Ints, sounds like you can use map to manipulate the input:
let arr = [0,1,0,1,0,1]
var sum = 0
let val = arr.map { (sum += $0, sum).1 }
print(val) // "[0, 1, 1, 2, 2, 3]\n"
I'll keep working on a solution that doesn't use an external variable.
I thought I'd be cool to extend Sequence with a generic scan function as is suggested in the great first answer.
Given this extension, you can get the running sum of an array like this: [1,2,3].scan(0, +)
But you can also get other interesting things…
Running product: array.scan(1, *)
Running max: array.scan(Int.min, max)
Running min: array.scan(Int.max, min)
Because the implementation is a function on Sequence and returns a Sequence, you can chain it together with other sequence functions. It is efficient, having linear running time.
Here's the extension…
extension Sequence {
func scan<Result>(_ initialResult: Result, _ nextPartialResult: #escaping (Result, Self.Element) -> Result) -> ScanSequence<Self, Result> {
return ScanSequence(initialResult: initialResult, underlying: self, combine: nextPartialResult)
}
}
struct ScanSequence<Underlying: Sequence, Result>: Sequence {
let initialResult: Result
let underlying: Underlying
let combine: (Result, Underlying.Element) -> Result
typealias Iterator = ScanIterator<Underlying.Iterator, Result>
func makeIterator() -> Iterator {
return ScanIterator(previousResult: initialResult, underlying: underlying.makeIterator(), combine: combine)
}
var underestimatedCount: Int {
return underlying.underestimatedCount
}
}
struct ScanIterator<Underlying: IteratorProtocol, Result>: IteratorProtocol {
var previousResult: Result
var underlying: Underlying
let combine: (Result, Underlying.Element) -> Result
mutating func next() -> Result? {
guard let nextUnderlying = underlying.next() else {
return nil
}
previousResult = combine(previousResult, nextUnderlying)
return previousResult
}
}
One solution using reduce:
func runningSum(array: [Int]) -> [Int] {
return array.reduce([], combine: { (result: [Int], item: Int) -> [Int] in
if result.isEmpty {
return [item] //first item, just take the value
}
// otherwise take the previous value and append the new item
return result + [result.last! + item]
})
}
I'm very late to this party. The other answers have good explanations. But none of them have provided the initial result, in a generic way. This implementation is useful to me.
public extension Sequence {
/// A sequence of the partial results that `reduce` would employ.
func scan<Result>(
_ initialResult: Result,
_ nextPartialResult: #escaping (Result, Element) -> Result
) -> AnySequence<Result> {
var iterator = makeIterator()
return .init(
sequence(first: initialResult) { partialResult in
iterator.next().map {
nextPartialResult(partialResult, $0)
}
}
)
}
}
extension Sequence where Element: AdditiveArithmetic & ExpressibleByIntegerLiteral {
var runningSum: AnySequence<Element> { scan(0, +).dropFirst() }
}
At first, I apologize for my English!
Please help me detect when I was wrong.
let arrayInt = [0, 1, 2, 3, 4, 5, 7, 8, 9]
func myF(array: [Int], cl:(n1: Int, n2: Int) -> Bool) -> Int {
var number : Int
for value in array {
if cl(n1: number, n2: value) {
number = value
}
}
return number
}
myF(arrayInt, { cl: (n1: Int, n2: Int) -> Bool in
return n1 < n2
})
The function takes an array of Int and closure returns Int. Closure should take two Int numbers and return Bool yes or no. It is necessary to walk in a loop through the array and compare elements of array with variable using closure . If closure returns yes, you write the value of the array into variable. At the end of the function returns the variable. We need find max and min value in array.
I have 3 issue:
consecutive statements on a line must be separated by ';'
expected expression
contextual type for closure argument list expects 2 arguments, which cannot be implicitly ignored
Please don't proposed me use method "sort()". I am learning of "closure".
First of all you need to initialize your number variable: var number : Int -> var number = 0
Second, the function call with closure is not correct. There are several ways to call a closure:
let y = myF(arrayInt, cl: { (n1: Int, n2: Int) -> Bool in
return n1 < n2
})
or
let x = myF(arrayInt) { (n1, n2) -> Bool in
return n1 < n2
}
or even
let z = myF(arrayInt) { n1, n2 in
return n1 < n2
}
and
let w = myF(arrayInt) { $0 < $1 }
This link and this one should help you
Full code sample:
let arrayInt = [1, 2, 3, 0, 4]
func myF(array: [Int], cl: (n1: Int, n2: Int) -> Bool) -> Int {
var number = 0
for i in array {
if cl(n1: number, n2: i) {
number = i
}
}
return number
}
let x = myF(arrayInt) { (n1, n2) -> Bool in
return n1 < n2
}
First replace:
myF(arrayInt, { cl: (n1: Int, n2: Int) -> Bool in
by:
myF(arrayInt, cl: { (n1: Int, n2: Int) -> Bool in
because cl is the parameter name and all included in { } is the closure.
Second initialize number in myF function replacing:
var number : Int
by:
var number = array[0]
if the goal of the closure is to find max or min value.