Reducing a list of points into a list of pairs of points I have some data…

let points = [(718, 620), (4596, 1280), (410, 333), (4597, 993), 
(410, 337), (4597, 996), (428, 337), (4597, 1000), (431, 335), (4599, 1044)]


… that follows the pattern

[(pointStartOne.x, pointStartOne.y), (pointEndOne.x, pointEndOne.y),
(pointStartTwo.x, pointStartTwo.x) // ... 


I need to structure it to 

typealias PointPair = [(start: Point, end: Point)]
struct Point {
    let x: Int
    let y: Int
}


Here is my code:

var result: PointPair = []
while i &lt; points.count{
    result.append((Point(x: points[i].0, y: points[i].1), Point(x: points[i+1].0, y: points[i+1].1)))
    i+=2
}


I think maybe it is nice situation to use functional programming reduce

Here is code ituitive:

let result = zip((points.enumerated().filter({ (offset: Int, element: (Int, Int)) -&gt; Bool in
        return offset%2==0
    })), (points.enumerated().filter({ (offset: Int, element: (Int, Int)) -&gt; Bool in
        return offset%2==1
    }))).reduce(PointPair(), { (result: PointPair, arg) -&gt; PointPair in
        let (one, other) = arg
        let (offset, point) = one
        let (offsetTwo, otherPoint) = other
        return result + [(Point(x: point.0,y: point.1), Point(x: otherPoint.0,y: otherPoint.1))]
    })


It is messy. Trying to use functional programming conveniently and elegantly.

Here is the improved code:

result = points.enumerated().reduce(into: PointPair(), {(temp, arg) in
        let (offset, point) = arg
        if offset % 2 == 0{
            temp += [(Point(x: point.0, y: point.1), Point(x: 0, y: 0) )]
        }
        else if let last = temp.last {
           temp[temp.count - 1] = (last.0, Point(x: point.0, y: point.1))
        }
    })
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.