Operations on array indices - swift

I am new to app development and need help with some simple logic. I have an array of float values. The calculation involves two entries in the array but needs to be repeated until every possible combination of entries have been calculated.
ie x = (2* entry2) -entry1
Obviously my only way of referencing these entries is with index numbers. So I would assume x=(2*array[id+1])-array[id]
However my sequence would need to step the second array id down, and once 0 is reached increment both array IDs +1 and repeat the process until the first ID has reached the maximum ID number.
Or am I going about this the wrong way. Any help would be appreciated.
Currently I have RFArray and I want to populate IMProdArray so my code would be:
IMProdArray+=[2*(RFArray[2])-(RFArray[1])]
But I need a loop to repeat this for all possible combinations of ID numbers in the array.
So If I had 4 entries in the Array:
IMProdArray+=[2*(RFArray[3])-(RFArray[2])]
IMProdArray+=[2*(RFArray[3])-(RFArray[1])]
IMProdArray+=[2*(RFArray[3])-(RFArray[0])]
IMProdArray+=[2*(RFArray[2])-(RFArray[1])]
IMProdArray+=[2*(RFArray[2])-(RFArray[0])]
IMProdArray+=[2*(RFArray[1])-(RFArray[0])]
And then the reverse the order for all ID numbers:
IMProdArray+=[2*(RFArray[2])-(RFArray[3])]
IMProdArray+=[2*(RFArray[1])-(RFArray[3])]
IMProdArray+=[2*(RFArray[0])-(RFArray[3])]
IMProdArray+=[2*(RFArray[1])-(RFArray[2])]
IMProdArray+=[2*(RFArray[0])-(RFArray[2])]
IMProdArray+=[2*(RFArray[0])-(RFArray[1])]
Thanks,
SamP

For example, define an Array extension with a function that returns all the pairwise combinations of its elements, then map over the pairs with the calculation you wish to perform:
extension Array {
func pairs() -> [(T, T)] {
// you can take this nested func out for reuse
func reverseIndexPairs(var count n: Int) -> [(Int, Int)] {
assert(n >= 0)
var ps = [(Int, Int)]()
for e1 in stride(from: n-1, through: 0, by: -1) {
n--
for e2 in stride(from: n-1, through: 0, by: -1) {
ps.append((e1, e2))
}
}
return ps
}
return reverseIndexPairs(count: self.count).map {
(self[$0.0], self[$0.1])
}
}
}
let arr: [Double] = [0,1,2,3]
println("test order: ")
for e in [0,1,2,3].pairs() {
println(e)
}
println("\nresult array <- 2 * x - y:")
let resultArray = arr.pairs().map { x, y in 2 * x - y }
for e in resultArray {
println(e)
}
println("\nresult array <- 2 * y - x:")
let resultReverse = arr.pairs().map { x, y in 2 * y - x }
for e in resultReverse {
println(e)
}
If I understood you right, you want the pairs to be in the reverse order, so the code above prints:
test order:
(3, 2)
(3, 1)
(3, 0)
(2, 1)
(2, 0)
(1, 0)
result array <- 2 * x - y:
4.0
5.0
6.0
3.0
4.0
2.0
result array <- 2 * y - x:
1.0
-1.0
-3.0
0.0
-2.0
-1.0

Related

Scala: Problem with foldLeft with negative numbers in list

I am writing a Scala function that returns the sum of even elements in a list, minus sum of odd elements in a list. I cannot use mutables, recursion or for/while loops for my solution. The code below passes 2/3 tests, but I can't seem to figure out why it can't compute the last test correctly.
def sumOfEvenMinusOdd(l: List[Int]) : Int = {
if (l.length == 0) return 0
val evens = l.filter(_%2==0)
val odds = l.filter(_%2==1)
val evenSum = evens.foldLeft(0)(_+_)
val oddSum = odds.foldLeft(0)(_+_)
evenSum-oddSum
}
//BEGIN TESTS
val i1 = sumOfEvenMinusOdd(List(1,3,5,4,5,2,1,0)) //answer: -9
val i2 = sumOfEvenMinusOdd(List(2,4,5,6,7,8,10)) //answer: 18
val i3 = sumOfEvenMinusOdd(List(109, 19, 12, 1, -5, -120, -15, 30,-33,-13, 12, 19, 3, 18, 1, -1)) //answer -133
My code is outputting this:
defined function sumOfEvenMinusOdd
i1: Int = -9
i2: Int = 18
i3: Int = -200
I am extremely confused why these negative numbers are tripping up the rest of my code. I saw a post explaining the order of operations with foldLeft foldRight, but even changing to foldRight still yields i3: Int = -200. Is there a detail I'm missing? Any guidance / help would be greatly appreciated.
The problem isn't foldLeft or foldRight, the problem is the way you filter out odd values:
val odds = l.filter(_ % 2 == 1)
Should be:
val odds = l.filter(_ % 2 != 0)
The predicate _ % 2 == 1 will only yield true for positive elements. For example, the expression -15 % 2 is equal to -1, and not 1.
As as side note, we can also make this a bit more efficient:
def sumOfEvenMinusOdd(l: List[Int]): Int = {
val (evenSum, oddSum) = l.foldLeft((0, 0)) {
case ((even, odd), element) =>
if (element % 2 == 0) (even + element, odd) else (even, odd + element)
}
evenSum - oddSum
}
Or even better by accumulating the difference only:
def sumOfEvenMinusOdd(l: List[Int]): Int = {
l.foldLeft(0) {
case (diff, element) =>
diff + element * (if (element % 2 == 0) 1 else -1)
}
}
The problem is on the filter condition that you apply on list to find odd numbers.
the odd condition that you doesn't work for negative odd number because mod 2 return -1 for this kind of number.
number % 2 == 0 if number is even
number % 2 != 0 if number is odd
so if you change the filter conditions all works as expected.
Another suggestion:
Why you want use foldleft function for a simple sum operation when you can use directly the sum functions?
test("Test sum Of even minus odd") {
def sumOfEvenMinusOdd(l: List[Int]) : Int = {
val evensSum = l.filter(_%2 == 0).sum
val oddsSum = l.filter(_%2 != 0).sum
evensSum-oddsSum
}
assert(sumOfEvenMinusOdd(List.empty[Int]) == 0)
assert(sumOfEvenMinusOdd(List(1,3,5,4,5,2,1,0)) == -9) //answer: -9
assert(sumOfEvenMinusOdd(List(2,4,5,6,7,8,10)) == 18) //answer: 18
assert(sumOfEvenMinusOdd(List(109, 19, 12, 1, -5, -120, -15, 30,-33,-13, 12, 19, 3, 18, 1, -1)) == -133)
}
With this solution your function is more clear and you can remove the if on the funciton

How to convert float to fraction in Swift [duplicate]

I am building a calculator and want it to automatically convert every decimal into a fraction. So if the user calculates an expression for which the answer is "0.333333...", it would return "1/3". For "0.25" it would return "1/4". Using GCD, as found here (Decimal to fraction conversion), I have figured out how to convert any rational, terminating decimal into a decimal, but this does not work on any decimal that repeats (like .333333).
Every other function for this on stack overflow is in Objective-C. But I need a function in my swift app! So a translated version of this (https://stackoverflow.com/a/13430237/5700898) would be nice!
Any ideas or solutions on how to convert a rational or repeating/irrational decimal to a fraction (i.e. convert "0.1764705882..." to 3/17) would be great!
If you want to display the results of calculations as rational numbers
then the only 100% correct solution is to use rational arithmetic throughout all calculations, i.e. all intermediate values are stored as a pair of integers (numerator, denominator), and all additions, multiplications, divisions, etc are done using the rules for rational
numbers.
As soon as a result is assigned to a binary floating point number
such as Double, information is lost. For example,
let x : Double = 7/10
stores in x an approximation of 0.7, because that number cannot
be represented exactly as a Double. From
print(String(format:"%a", x)) // 0x1.6666666666666p-1
one can see that x holds the value
0x16666666666666 * 2^(-53) = 6305039478318694 / 9007199254740992
≈ 0.69999999999999995559107901499373838305
So a correct representation of x as a rational number would be
6305039478318694 / 9007199254740992, but that is of course not what
you expect. What you expect is 7/10, but there is another problem:
let x : Double = 69999999999999996/100000000000000000
assigns exactly the same value to x, it is indistinguishable from
0.7 within the precision of a Double.
So should x be displayed as 7/10 or as 69999999999999996/100000000000000000 ?
As said above, using rational arithmetic would be the perfect solution.
If that is not viable, then you can convert the Double back to
a rational number with a given precision.
(The following is taken from Algorithm for LCM of doubles in Swift.)
Continued Fractions
are an efficient method to create a (finite or infinite) sequence of fractions hn/kn that are arbitrary good approximations to a given real number x,
and here is a possible implementation in Swift:
typealias Rational = (num : Int, den : Int)
func rationalApproximationOf(x0 : Double, withPrecision eps : Double = 1.0E-6) -> Rational {
var x = x0
var a = floor(x)
var (h1, k1, h, k) = (1, 0, Int(a), 1)
while x - a > eps * Double(k) * Double(k) {
x = 1.0/(x - a)
a = floor(x)
(h1, k1, h, k) = (h, k, h1 + Int(a) * h, k1 + Int(a) * k)
}
return (h, k)
}
Examples:
rationalApproximationOf(0.333333) // (1, 3)
rationalApproximationOf(0.25) // (1, 4)
rationalApproximationOf(0.1764705882) // (3, 17)
The default precision is 1.0E-6, but you can adjust that to your needs:
rationalApproximationOf(0.142857) // (1, 7)
rationalApproximationOf(0.142857, withPrecision: 1.0E-10) // (142857, 1000000)
rationalApproximationOf(M_PI) // (355, 113)
rationalApproximationOf(M_PI, withPrecision: 1.0E-7) // (103993, 33102)
rationalApproximationOf(M_PI, withPrecision: 1.0E-10) // (312689, 99532)
Swift 3 version:
typealias Rational = (num : Int, den : Int)
func rationalApproximation(of x0 : Double, withPrecision eps : Double = 1.0E-6) -> Rational {
var x = x0
var a = x.rounded(.down)
var (h1, k1, h, k) = (1, 0, Int(a), 1)
while x - a > eps * Double(k) * Double(k) {
x = 1.0/(x - a)
a = x.rounded(.down)
(h1, k1, h, k) = (h, k, h1 + Int(a) * h, k1 + Int(a) * k)
}
return (h, k)
}
Examples:
rationalApproximation(of: 0.333333) // (1, 3)
rationalApproximation(of: 0.142857, withPrecision: 1.0E-10) // (142857, 1000000)
Or – as suggested by #brandonscript – with a struct Rational and an initializer:
struct Rational {
let numerator : Int
let denominator: Int
init(numerator: Int, denominator: Int) {
self.numerator = numerator
self.denominator = denominator
}
init(approximating x0: Double, withPrecision eps: Double = 1.0E-6) {
var x = x0
var a = x.rounded(.down)
var (h1, k1, h, k) = (1, 0, Int(a), 1)
while x - a > eps * Double(k) * Double(k) {
x = 1.0/(x - a)
a = x.rounded(.down)
(h1, k1, h, k) = (h, k, h1 + Int(a) * h, k1 + Int(a) * k)
}
self.init(numerator: h, denominator: k)
}
}
Example usage:
print(Rational(approximating: 0.333333))
// Rational(numerator: 1, denominator: 3)
print(Rational(approximating: .pi, withPrecision: 1.0E-7))
// Rational(numerator: 103993, denominator: 33102)
So a little late here, but I had a similar problem and ended up building Swift FractionFormatter. This works because most of the irrational numbers you care about are part of the set of vulgar, or common fractions and are easy to validate proper transformation. The rest may or may not round, but you get very close on any reasonable fraction your user might generate. It is designed to be a drop in replacement for NumberFormatter.
As Martin R said, the Only way to have (99.99%)exact calculations, is to calculate everything with rational numbers, from beginning to the end.
the reason behind the creation of this class was also the fact that i needed to have very accurate calculations, and that was not possible with the swift-provided types. so i created my own type.
here is the code, i'll explain it below.
class Rational {
var alpha = 0
var beta = 0
init(_ a: Int, _ b: Int) {
if (a > 0 && b > 0) || (a < 0 && b < 0) {
simplifier(a,b,"+")
}
else {
simplifier(a,b,"-")
}
}
init(_ double: Double, accuracy: Int = -1) {
exponent(double, accuracy)
}
func exponent(_ double: Double, _ accuracy: Int) {
//Converts a double to a rational number, in which the denominator is of power of 10.
var exp = 1
var double = double
if accuracy != -1 {
double = Double(NSString(format: "%.\(accuracy)f" as NSString, double) as String)!
}
while (double*Double(exp)).remainder(dividingBy: 1) != 0 {
exp *= 10
}
if double > 0 {
simplifier(Int(double*Double(exp)), exp, "+")
}
else {
simplifier(Int(double*Double(exp)), exp, "-")
}
}
func gcd(_ alpha: Int, _ beta: Int) -> Int {
// Calculates 'Greatest Common Divisor'
var inti: [Int] = []
var multi = 1
var a = Swift.min(alpha,beta)
var b = Swift.max(alpha,beta)
for idx in 2...a {
if idx != 1 {
while (a%idx == 0 && b%idx == 0) {
a = a/idx
b = b/idx
inti.append(idx)
}
}
}
inti.map{ multi *= $0 }
return multi
}
func simplifier(_ alpha: Int, _ beta: Int, _ posOrNeg: String) {
//Simplifies nominator and denominator (alpha and beta) so they are 'prime' to one another.
let alpha = alpha > 0 ? alpha : -alpha
let beta = beta > 0 ? beta : -beta
let greatestCommonDivisor = gcd(alpha,beta)
self.alpha = posOrNeg == "+" ? alpha/greatestCommonDivisor : -alpha/greatestCommonDivisor
self.beta = beta/greatestCommonDivisor
}
}
typealias Rnl = Rational
func *(a: Rational, b: Rational) -> Rational {
let aa = a.alpha*b.alpha
let bb = a.beta*b.beta
return Rational(aa, bb)
}
func /(a: Rational, b: Rational) -> Rational {
let aa = a.alpha*b.beta
let bb = a.beta*b.alpha
return Rational(aa, bb)
}
func +(a: Rational, b: Rational) -> Rational {
let aa = a.alpha*b.beta + a.beta*b.alpha
let bb = a.beta*b.beta
return Rational(aa, bb)
}
func -(a: Rational, b: Rational) -> Rational {
let aa = a.alpha*b.beta - a.beta*b.alpha
let bb = a.beta*b.beta
return Rational(aa, bb)
}
extension Rational {
func value() -> Double {
return Double(self.alpha) / Double(self.beta)
}
}
extension Rational {
func rnlValue() -> String {
if self.beta == 1 {
return "\(self.alpha)"
}
else if self.alpha == 0 {
return "0"
}
else {
return "\(self.alpha) / \(self.beta)"
}
}
}
// examples:
let first = Rnl(120,45)
let second = Rnl(36,88)
let third = Rnl(2.33435, accuracy: 2)
let forth = Rnl(2.33435)
print(first.alpha, first.beta, first.value(), first.rnlValue()) // prints 8 3 2.6666666666666665 8 / 3
print((first*second).rnlValue()) // prints 12 / 11
print((first+second).rnlValue()) // prints 203 / 66
print(third.value(), forth.value()) // prints 2.33 2.33435
First of all, we have the class itself. the class can be initialised in two ways:
in the Rational class, alpha ~= nominator & beta ~= denominator
The First way is initialising the class using two integers, first of with is the nominator, and the second one is the denominator. the class gets those two integers, and then reduces them to the least numbers possible. e.g reduces (10,5) to (2,1) or as another example, reduces (144, 60) to (12,5). this way, always the simplest numbers are stored.
this is possible using the gcd (greatest common divisor) function and simplifier function, which are not hard to understand from the code.
the only thing is that the class faces some issues with negative numbers, so it always saves whether the final rational number is negative or positive, and if its negative it makes the nominator negative.
The Second way to initialise the class, is with a double, and with an optional parameter called 'accuracy'. the class gets the double, and also the accuracy of how much numbers after decimal point you need, and converts the double to a nominator/denominator form, in which the denominator is of power of 10. e.g 2.334 will be 2334/1000 or 342.57 will be 34257/100. then tries to simplify the rational numbers using the same method which was explained in the #1 way.
After the class definition, there is type-alias 'Rnl', which you can obviously change it as you wish.
Then there are 4 functions, for the 4 main actions of math: * / + -, which i defined so e.g. you can easily multiply two numbers of type Rational.
After that, there are 2 extensions to Rational type, first of which ('value') gives you the double value of a Rational number, the second one ('rnlValue') gives you the the Rational number in form of a human-readable string: "nominator / denominator"
At last, you can see some examples of how all these work.

In Swift 3, how to calculate the factorial when the result becomes too high?

I have written this function to return the factorial of a given number
func factorial(_ n: Int) -> Int {
if n == 0 {
return 1
}
else {
return n * factorial(n - 1)
}
}
print( factorial(20) ) // 2432902008176640000
Works as it should, as long the given number does not exceed 20, because then the result becomes too high!
How can I circumvent this limit and thus calculate the factorial of higher numbers?
I have searched around and found some bignum libraries for Swift. I'm doing this to learn and be familiar with Swift, therefore I want to figure this out on my own.
Here's an approach that will let you find very large factorials.
Represent large numbers as an array of digits. For instance 987 would be [9, 8, 7]. Multiplying that number by an integer n would require two steps.
Multiply each value in that array by n.
Perform a carry operation to return a result that is again single digits.
For example 987 * 2:
let arr = [9, 8, 7]
let arr2 = arr.map { $0 * 2 }
print(arr2) // [18, 16, 14]
Now, perform the carry operation. Starting at the one's digit, 14 is too big, so keep the 4 and carry the 1. Add the 1 to 16 to get 17.
[18, 17, 4]
Repeat with the ten's place:
[19, 7, 4]
And then with the hundred's place:
[1, 9, 7, 4]
Finally, for printing, you could convert this back to a string:
let arr = [1, 9, 7, 4]
print(arr.map(String.init).joined())
1974
Applying that technique, here is a carryAll function that performs the carry operation, and a factorial that uses it to calculate very large factorials:
func carryAll(_ arr: [Int]) -> [Int] {
var result = [Int]()
var carry = 0
for val in arr.reversed() {
let total = val + carry
let digit = total % 10
carry = total / 10
result.append(digit)
}
while carry > 0 {
let digit = carry % 10
carry = carry / 10
result.append(digit)
}
return result.reversed()
}
func factorial(_ n: Int) -> String {
var result = [1]
for i in 2...n {
result = result.map { $0 * i }
result = carryAll(result)
}
return result.map(String.init).joined()
}
print(factorial(1000))
402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
You can use this library:
BigInt
Install it using CocoaPods:
pod 'BigInt'
Then you can use it like this:
import BigInt
func factorial(_ n: Int) -> BigInt {
if n == 0 {
return 1
}
else {
return BigInt(n) * factorial(n - 1)
}
}
print( factorial(50) ) // 30414093201713378043612608166064768844377641568960512000000000000

CoffeeScript reduce skips values that are the same

I am using CoffeeScript to aggregate elements from a list into a combined object. However, when I have two values that are the same, one of the values gets left out. Instead of skipping one of these values, how can I get their sum?
metals = [
{ metal: 'silver', amount: 10 }
{ metal: 'gold', amount: 16 }
{ metal: 'iron', amount: 17 }
{ metal: 'iron', amount: 3 }
]
reduction = metals.reduce (x, y) ->
x[y.metal]= y.amount
x
, {}
console.log reduction
# => { silver: 10, gold: 16, iron: 3 }, but I would like to get iron: 20
here is a jsfiddle to help solve the problem https://jsfiddle.net/822trwez/
If you want reduce to sum things then you have to say so:
reduction = metals.reduce (x, y) ->
x[y.metal] = (x[y.metal] ? 0) + y.amount
x
, { }
The x[y.metal] ? 0 is just saying "if x[y.metal] is defined then use it, otherwise use 0". You could also say:
reduction = metals.reduce (x, y) ->
x[y.metal] = (x[y.metal] || 0) + y.amount
x
, { }
since you don't care about falsey values for x[y.metal] such as 0, '', false, null, or undefined; in your case you can convert all those to zero.
You could also be more explicit about what you're doing:
reduction = metals.reduce (x, y) ->
x[y.metal] = 0 if(y.metal !of x)
x[y.metal] += y.amount
x
, {}
The x[y.metal] = 0 if(y.metal !of x) just initializes x[y.metal] to zero if x doesn't have a y.metal property already. You could also use unless if you don't like !of:
reduction = metals.reduce (x, y) ->
x[y.metal] = 0 unless(y.metal of x)
x[y.metal] += y.amount
x
, {}
Keep in mind that all reduce does is runs the function you give it and feeds the function's output back to itself so:
[1,2,3].reduce f, i
is just:
f(f(f(i, 1), 2), 3)
What the function f does with its inputs and what it returns is up to you.

List comprehension in Swift

The language guide has revealed no trace of list comprehension. What's the neatest way of accomplishing this in Swift? I'm looking for something similar to:
evens = [ x for x in range(10) if x % 2 == 0]
As of Swift 2.x, there are a few short equivalents to your Python-style list comprehension.
The most straightforward adaptations of Python's formula (which reads something like "apply a transform to a sequence subject to a filter") involve chaining the map and filter methods available to all SequenceTypes, and starting from a Range:
// Python: [ x for x in range(10) if x % 2 == 0 ]
let evens = (0..<10).filter { $0 % 2 == 0 }
// Another example, since the first with 'x for x' doesn't
// use the full ability of a list comprehension:
// Python: [ x*x for x in range(10) if x % 2 == 0 ]
let evenSquared = (0..<10).filter({ $0 % 2 == 0 }).map({ $0 * $0 })
Note that a Range is abstract — it doesn't actually create the whole list of values you ask it for, just a construct that lazily supplies them on demand. (In this sense it's more like Python's xrange.) However, the filter call returns an Array, so you lose the "lazy" aspect there. If you want to keep the collection lazy all the way through, just say so:
// Python: [ x for x in range(10) if x % 2 == 0 ]
let evens = (0..<10).lazy.filter { $0 % 2 == 0 }
// Python: [ x*x for x in range(10) if x % 2 == 0 ]
let evenSquared = (0..<10).lazy.filter({ $0 % 2 == 0 }).map({ $0 * $0 })
Unlike the list comprehension syntax in Python (and similar constructs in some other languages), these operations in Swift follow the same syntax as other operations. That is, it's the same style of syntax to construct, filter, and operate on a range of numbers as it is to filter and operate on an array of objects — you don't have to use function/method syntax for one kind of work and list comprehension syntax for another.
And you can pass other functions in to the filter and map calls, and chain in other handy transforms like sort and reduce:
// func isAwesome(person: Person) -> Bool
// let people: [Person]
let names = people.filter(isAwesome).sort(<).map({ $0.name })
let sum = (0..<10).reduce(0, combine: +)
Depending on what you're going for, though, there may be more concise ways to say what you mean. For example, if you specifically want a list of even integers, you can use stride:
let evenStride = 0.stride(to: 10, by: 2) // or stride(through:by:), to include 10
Like with ranges, this gets you a generator, so you'll want to make an Array from it or iterate through it to see all the values:
let evensArray = Array(evenStride) // [0, 2, 4, 6, 8]
Edit: Heavily revised for Swift 2.x. See the edit history if you want Swift 1.x.
With Swift 5, you can choose one of the seven following Playground sample codes in order to solve your problem.
#1. Using stride(from:to:by:) function
let sequence = stride(from: 0, to: 10, by: 2)
let evens = Array(sequence)
// let evens = sequence.map({ $0 }) // also works
print(evens) // prints [0, 2, 4, 6, 8]
#2. Using Range filter(_:) method
let range = 0 ..< 10
let evens = range.filter({ $0 % 2 == 0 })
print(evens) // prints [0, 2, 4, 6, 8]
#3. Using Range compactMap(_:) method
let range = 0 ..< 10
let evens = range.compactMap({ $0 % 2 == 0 ? $0 : nil })
print(evens) // prints [0, 2, 4, 6, 8]
#4. Using sequence(first:next:) function
let unfoldSequence = sequence(first: 0, next: {
$0 + 2 < 10 ? $0 + 2 : nil
})
let evens = Array(unfoldSequence)
// let evens = unfoldSequence.map({ $0 }) // also works
print(evens) // prints [0, 2, 4, 6, 8]
#5. Using AnySequence init(_:) initializer
let anySequence = AnySequence<Int>({ () -> AnyIterator<Int> in
var value = 0
return AnyIterator<Int> {
defer { value += 2 }
return value < 10 ? value : nil
}
})
let evens = Array(anySequence)
// let evens = anySequence.map({ $0 }) // also works
print(evens) // prints [0, 2, 4, 6, 8]
#6. Using for loop with where clause
var evens = [Int]()
for value in 0 ..< 10 where value % 2 == 0 {
evens.append(value)
}
print(evens) // prints [0, 2, 4, 6, 8]
#7. Using for loop with if condition
var evens = [Int]()
for value in 0 ..< 10 {
if value % 2 == 0 {
evens.append(value)
}
}
print(evens) // prints [0, 2, 4, 6, 8]
Generally, a list comprehension in Python can be written in the form:
[f(x) for x in xs if g(x)]
Which is the same as
map(f, filter(g, xs))
Therefore, in Swift you can write it as
listComprehension<Y>(xs: [X], f: X -> Y, g: X -> Bool) = map(filter(xs, g), f)
For example:
map(filter(0..<10, { $0 % 2 == 0 }), { $0 })
As of Swift 2 you can do something like this:
var evens = [Int]()
for x in 1..<10 where x % 2 == 0 {
evens.append(x)
}
// or directly filtering Range due to default implementations in protocols (now a method)
let evens = (0..<10).filter{ $0 % 2 == 0 }
Got to admit, I am surprised nobody mentioned flatmap, since I think it's the closest thing Swift has to list (or set or dict) comprehension.
var evens = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].flatMap({num -> Int? in
if num % 2 == 0 {return num} else {return nil}
})
Flatmap takes a closure, and you can either return individual values (in which case it will return an array with all of the non-nil values and discard the nils) or return array segments (in which case it will catenate all of your segments together and return that.)
Flatmap seems mostly (always?) to be unable to infer return values. Certainly, in this case it can't, so I specify it as -> Int? so that I can return nils, and thus discard the odd elements.
You can nest flatmaps if you like. And I find them much more intuitive (although obviously also a bit more limited) than the combination of map and filter. For example, the top answer's 'evens squared', using flatmap, becomes,
var esquares = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].flatMap({num -> Int? in
if num % 2 == 0 {return num * num} else {return nil}
})
The syntax isn't quite as one-line not-quite-the-same-as-everything-else as python's is. I'm not sure if I like that less (because for the simple cases in python it's very short and still very readable) or more (because complex cases can get wildly out of control, and experienced python programmers often think that they're perfectly readable and maintainable when a beginner at the same company can take half an hour to puzzle out what it was intended to do, let alone what it's actually doing.)
Here is the version of flatMap from which you return single items or nil, and here is the version from which you return segments.
It's probably also worth looking over both array.map and array.forEach, because both of them are also quite handy.
One aspect of list comprehension that hasn't been mentioned in this thread is the fact that you can apply it to multiple lists' Cartesian product. Example in Python:
[x + y for x in range(1,6) for y in range(3, 6) if x % 2 == 0]
… or Haskell:
[x+y | x <- [1..5], y <- [3..5], x `mod` 2 == 0]
In Swift, the 2-list equivalent logic is
list0
.map { e0 in
list1.map { e1 in
(e0, e1)
}
}
.joined()
.filter(f)
.map(g)
And we'd have to increase the nesting level as the number of lists in input increases.
I recently made a small library to solve this problem (if you consider it a problem). Following my first example, with the library we get
Array(1...5, 3...5, where: { n, _ in n % 2 == 0}) { $0 + $1 }
The rationale (and more about list comprehension in general) is explained in an blog post.
One way would be :
var evens: Int[]()
for x in 0..<10 {
if x%2 == 0 {evens += x} // or evens.append(x)
}
Range operators
Arrays
Here's an extension to the Array types that combines filter and map into one method:
extension Array {
func filterMap(_ closure: (Element) -> Element?) -> [Element] {
var newArray: [Element] = []
for item in self {
if let result = closure(item) {
newArray.append(result)
}
}
return newArray
}
}
It's similar to map except you can return nil to indicate that you don't want the element to be added to the new array. For example:
let items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let newItems = items.filterMap { item in
if item < 5 {
return item * 2
}
return nil
}
This could also be written more concisely as follows:
let newItems = items.filterMap { $0 < 5 ? $0 * 2 : nil }
In both of these examples, if the element is less than 5, then it is multiplied by two and added to the new array. If the closure returns nil, then the element is not added. Therefore, newIems is [2, 4, 6, 8].
Here's the Python equivalent:
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
newItems = [n * 2 for n in items if n < 5]