Vince O'Sullivan Vince O'Sullivan - 7 months ago 19
Swift Question

Swift List Product

Given two lists in Swift:

let rows = ["a", "b", "c"]
let cols = ["1", "2", "3"]


Is it possible to combine them using list comprehension to produce the following:

squares = ["a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3"]


Obviously, it can be done using a "for loop" and similar constructs, but I'm specifically for a list comprehension based solution. I know Swift can do some list comprehension (e.g. let evens = Array(filter(1..<10) { $0 % 2 == 0 }) ) but can't figure out if it can do something similar to the following piece of Haskell:

let squares = [ r ++ c | r <- rows, c <- cols]

Answer

A possible solution (now updated for Swift 2):

let rows = ["a", "b", "c"]
let cols = ["1", "2", "3"]

let squares = rows.flatMap {
    row in
    cols.map {
        col in
        row + col
    }
}
print(squares)
// [a1, a2, a3, b1, b2, b3, c1, c2, c3]

The inner map() maps the cols array to an array with the row number prepended to each entry. The outer flatMap() maps the rows array to an array of arrays (one for each row) and flattens the result.

Slightly more general, one could define the "product" of two sequences as an array of tuples (pairs) with all combinations:

func product<S : SequenceType, T : SequenceType>(lseq : S, _ rseq : T) -> [(S.Generator.Element, T.Generator.Element)] {
    return lseq.flatMap { left in
        rseq.map { right in
            (left, right)
        }
    }
}

and then use it as

let squares = product(rows, cols).map(+)