I have the following code in my project:
// typealias B = SomeType
// let partitions: [[B]] = ...
let pairsAcrossPartitions = Array(partitions.enumerated()).flatMap { (p1: (Int, [B])) -> [(Int, Int, B, B)] in
let (i, partition1) = p1
return Array(partitions.enumerated()).flatMap { (p2: (Int, [B])) -> [(Int, Int, B, B)] in
let (j, partition2) = p2
return partition1.flatMap { (el1: B) -> [(Int, Int, B, B)] in
return partition2.map { (el2: B) -> (Int, Int, B, B) in
return (i, j, el1, el2)
}
}
}
}
This returns a cartesian product of sorts: It returns all pairs (i, j, el1, el2)
where e1 is from partition i and e2 is from partition j.
The nested flatMap
-> flatMap
-> ... -> map
is kind of ugly, and I wonder if there's a better way to do this. In other languages, there are constructs for this, e.g. in Scala there are for-expressions (which do actually de-sugar into the same kind of code), Haskell has list comprehensions and do-notation, etc.
I've seen that there is some way to emulate list comprehensions with the Array initializer, but I don't think this would work in this case because the later steps in the comprehension depend on the result of the previous ones.