List comprehension in Swift - 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]

Related

How to remove filtered element from dictionary?

var scores: [String: Int] = ["Alex" : 4, "Rocco": 5, "Britney": 3, "Chad": 2, "John": 5]
func removeStudent() -> [String: Int]{
let filtered = scores.filter{ $0.value < 3}
return filtered
}
Your code filters your dictionary to those entries who's value is < 3. You want to remove those values from the dictionary instead? So rewrite your filter statement to select the items you want to keep instead of the ones you want to get rid of.
In that case, you need a filter closure that gives you the inverse (everything but the items you are currently filtering).
The inverse of < 3 is >= 3. So rewrite your filter statement as:
func studentsToKeep() -> [String: Int]{
let keep = scores.filter{ $0.value >= 3}
return keep
}

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

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

Swift - how to reduce matrix

I have an 3 dimension array (array[x][y][z], x y z can flexible)
var array = [ [[1,1,1],[0,0,0],[1,1,1]],
[[1,0,1],[1,0,1],[1,0,1]],
[[1,1,1],[0,0,0],[1,1,1]]
]
How can I reduce 3D to 2D to : array[z][y]
[3,1,3],[2,0,2],[3,1,3]
I read the instruction here but couldn't figure out how to apply to mine.
Updated :
Here is the logic
Let's start by forming a utility function as an extension on a matrix-style array ("cw" means column-wise):
extension Array where Element == [[Int]] {
func cwsum(_ ix1:Int, _ ix2:Int) -> Int {
return reduce(0) {$0 + $1[ix1][ix2]}
}
}
Then if the array is:
let array = [[[1,1,1],[0,0,0],[1,1,1]],
[[1,0,1],[1,0,1],[1,0,1]],
[[1,1,1],[0,0,0],[1,1,1]]]
... then the answer is:
[[array.cwsum(0,0), array.cwsum(1,0), array.cwsum(2,0)],
[array.cwsum(0,1), array.cwsum(1,1), array.cwsum(2,1)],
[array.cwsum(0,2), array.cwsum(1,2), array.cwsum(2,2)]]
// [[3, 1, 3], [2, 0, 2], [3, 1, 3]]
But wait — I think I see a pattern here! We can rewrite that without hard-coding the indices, as:
var result = [[Int]]()
for j in 0..<3 {
var r1 = [Int]()
for i in 0..<3 {
r1.append(array.cwsum(i,j))
}
result.append(r1)
} // result is now [[3, 1, 3], [2, 0, 2], [3, 1, 3]]
Okay, but where we can loop and append, we can map instead, thus turning i into the map variable:
var result = [[Int]]()
for j in 0..<3 {
result.append((0..<3).map{i in array.cwsum(i,j)})
}
But then we can do that for j as well — and thus it becomes a single line:
result = (0..<3).map{j in (0..<3).map{i in array.cwsum(i,j)}}
Since it sounds like you’re looking for a functional programming one-liner, here’s your answer:
array.indices.map{ j in array.indices.map{ i in array.map{ $0[i][j] }.reduce(0, +) } }
It’s basically the same as this code, which, while much longer, I consider much easier to read and gives me fewer headaches to reason about.
func flatten2(_ array:[[[Int]]]) -> [[Int]]
{
var result:[[Int]] = []
for j in 0..<array.count
{
var row:[Int] = []
for i in 0..<array.count
{
row.append(array.map{ $0[i][j] }.reduce(0, +))
}
result.append(row)
}
return result
}
Keep in mind the one-liner will take over two orders of magnitude longer to compile, since the Swift compiler is not very optimized for functional and closure programming, and so it has to construct enormous overload trees to parse that expression. As I suspect this is a question from a practice exam for a CS final, please, please, make your poor TA’s life easier and use the multi-liner.
Given this
let matrix = [
[[1,1,1],[0,0,0],[1,1,1]],
[[1,0,1],[1,0,1],[1,0,1]],
[[1,1,1],[0,0,0],[1,1,1]]
]
lets calculate these
let all = matrix.joined().enumerated()
let a = all.filter { $0.offset % 3 == 0 }.map { $0.element[0] }.reduce(0, +)
let b = all.filter { $0.offset % 3 == 1 }.map { $0.element[0] }.reduce(0, +)
let c = all.filter { $0.offset % 3 == 2 }.map { $0.element[0] }.reduce(0, +)
let d = all.filter { $0.offset % 3 == 0 }.map { $0.element[1] }.reduce(0, +)
let e = all.filter { $0.offset % 3 == 1 }.map { $0.element[1] }.reduce(0, +)
let f = all.filter { $0.offset % 3 == 2 }.map { $0.element[1] }.reduce(0, +)
let g = all.filter { $0.offset % 3 == 0 }.map { $0.element[2] }.reduce(0, +)
let h = all.filter { $0.offset % 3 == 1 }.map { $0.element[2] }.reduce(0, +)
let i = all.filter { $0.offset % 3 == 2 }.map { $0.element[2] }.reduce(0, +)
and finally lets put the values together
let res = [[a, b, c], [d, e, f], [g, h, i]]
After hours of attempts. This is my output, it's very simple and unrelated to reduce. The inputs of 3d array are flexible x,y,z
let x = array.count
let y = array[0].count
let z = array[0][0].count
var final = Array(repeating: Array(repeating: 0, count: y), count: z)
for i in 0..<z {
for ii in 0..<y {
var sum = 0
for iii in 0..<x {
sum = sum + array[iii][ii][i]
}
final[i][ii] = sum
}
}

Operations on array indices

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