Reducing a list of points into a list of pairs of points
Let's start with the first version: A loop 

var i = 0
while i &lt; points.count {
    // ...
    i += 2
}


can be written as a for-loop over a stride:

for i in stride(from: 0, to: points.count, by: 2) {
    // ...
}


which restricts the scope of i to the loop body, and makes it a constant. Now each loop iteration appends exactly one element to var result: PointPair, which means that we can write this as a map operation:

let result: PointPair = stride(from: 0, to: points.count, by: 2)
    .map { i in
        (start: Point(x: points[i].0, y: points[i].1),
         end: Point(x: points[i+1].0, y: points[i+1].1))
    }


This may already be the “functional” version that you are looking for, but let's also have a look at your other two variants.

The “intuitive code” creates two additional arrays by filtering the original one for even/odd indices. After filtering the arrays the offsets are not needed, giving the warnings


Immutable value 'offset' was never used; consider replacing with '_' or removing it
Immutable value 'offsetTwo' was never used; consider replacing with '_' or removing it


This can be fixed with

let (_, point) = one
let (_, otherPoint) = other


A better way is to use compactMap() (which can be thought of as a combination of filter() and map()) to create arrays of the points with even/odd indices, without the element offsets.

Using reduce() for creating the result array is inefficient, as it creates intermediate arrays for each iteration. reduce(into:_:) would be an improvement, but actually this is just a map():

let result: PointPair = zip(
    points.enumerated().compactMap { (offset, element) -&gt; Point? in
        offset % 2 == 0 ? Point(x: element.0, y: element.1) : nil },
    points.enumerated().compactMap { (offset, element) -&gt; Point? in
        offset % 2 == 1 ? Point(x: element.0, y: element.1) : nil }
).map { ($0, $1) }


This looks a lot “less messy” than your original version, but still has the disadvantage of creating intermediate arrays.

I have not much to say about your last version. It uses reduce(into:) which is good to avoid the creation of intermediate arrays. The only disadvantage is that temporary pairs are created and modified in every second step.

So the  “stride + map” variant looks like the best to me: It is efficient and easy to read.

A final remark: The type alias 

typealias PointPair = [(start: Point, end: Point)]


is misleading, because it does not define a pair of points but an array of pairs of points. I would probably define a dedicated type for a pair of points instead

struct Line {
    let from: Point
    let to: Point
}


and then use [Line]  as the result type.