配列の一部範囲を取り出して新しい配列を生成する方法のパフォーマンス比較

Swift の配列の `subscript` では `Int` 型だけでなく、`Range<Int>` 型も対応しています。つまり

```swift
let array = [Int](0 ..< 10000)
let number = array[1000] // number = 1000
```

だけでなく、

```swift
let array = [Int](0 ..< 10000)
let slice = array[1000 ..< 2000] // slice = [1000, 1001, 1002, ..., 1999]
```

も使えるのです。ただしこの場合、`slice` は `ArraySlice` 型であり、`Array` 型ではありません。何が違うかというと `slice` の `subscript` では `array` のものに対応し、`slice[1000] == 1000` になります（ちなみに `slice[0]` は存在しないのでアクセスしようとするとランタイムエラーになります）。ですので `Array` 型に変換するにはもう少し手間をかける必要があり、

```swift
let array = [Int](0 ..< 10000)
let newArray = Array(array[1000 ..< 2000]) // newArray = [1000, 1001, 1002, ..., 1999]
```

になります。こうすることでちゃんと `newArray[0] == 1000` になります。

さて、おさらいはここまでにして、何が言いたいかというと、配列の一部範囲から要素を取り出して新しい配列を作るのに主には 2 通りの方法があります（もし他にありましたら教えてください m(_  _)m）。一つは `map` を使う方法です：

```swift
let array = [Int](0 ..< 10000)
let range = 4000 ..< 5000
let newArray = range.map { (i) -> Int in
	return array[i]
}
```

そしてもう一つの方法は先ほどおさらいした通り直接 `subscript` に `Range<Int>` を代入する方法です：

```swift
let array = [Int](0 ..< 10000)
let range = 4000 ..< 5000
let newArray = Array(array[range])
```

では、この 2 通りの方法のパフォーマンスはどういったものでしょうか？とりあえず確認して見たいと思います。適当に swift ソースファイルを作ってコンパイルして実行してみましょう：

```swift
var baseArray = [Int](0 ..< 10000)
let childArray1Range = 3000 ..< 3050
let childArray2Range = 7000 ..< 7100

baseArray = baseArray.map { (i) -> Int in
	return i * i
}

let start1 = NSDate()
for _ in 0 ..< 10000 {
	let childArray1 = childArray1Range.map { (i) -> Int in
		return baseArray[i]
	}
	let childArray2 = childArray2Range.map { (i) -> Int in
		return baseArray[i]
	}
}
print(-start1.timeIntervalSinceNow)

let start2 = NSDate()
for _ in 0 ..< 10000 {
	let childArray1 = Array(baseArray[childArray1Range])
	let childArray2 = Array(baseArray[childArray2Range])
}
print(-start2.timeIntervalSinceNow)
```

上記の方法でとりあえずベースとなる配列 `baseArray` を作って、それぞれ `map` と `slice` の方法で生成してみて、それを 10000 回ループして実行タイムを計ってみました。そして肝心な結果は自分のパソコン（2013 モデルの MacBook Pro 15" Retina）ではこのようになります：
0.170238018035889
0.19194096326828

はい、ちょっと予想外の結果かもしれませんが、なんとループを回す `map` の方がわずかに早かったのです。つまり非常にパフォーマンス重視のシナリオ（例えば SpriteKit の毎秒 60 回呼び出される `update(currentTime: NSTimeInterval)` メソッドとか）では基本的には `map` で配列を作った方が早い、ということになります。まあもっとも、10000 回実行しても 0.02 秒の差しかないから別に言うほどパフォーマンスに影響はなさそうですけどね。

ところがこれはマルチスレッドを全く考えていないパターンですが、実際のアプリ制作にマルチスレッドを考慮しないことはあまりないじゃないかと思います。特にゲームの場合何でもかんでもメインスレッドに処理させてはいけないのでほぼ確実にマルチスレッド処理が必要です。そうすると、データの処理を一つの専用スレッド（というより正確にはキューですが）に任せるパターンもあるじゃないかと思います。何も考えずにどのスレッドでもデータの操作出来るようにしちゃうと処理が前後してしまって正しいデータが取れなくなってしまうこともありますから。というわけで、上記の処理に、さらにデータ処理スレッドを入れてみたパターンを追加してみましょう：

```swift
let queue = dispatch_queue_create("data", DISPATCH_QUEUE_SERIAL)
var baseArray = [Int](0 ..< 10000)
let childArray1Range = 3000 ..< 3050
let childArray2Range = 7000 ..< 7100

dispatch_sync(queue) { () -> Void in
	baseArray = baseArray.map { (i) -> Int in
		return i * i
	}
}

func getElement(i: Int) -> Int {
	var result = 0
	dispatch_sync(queue) { () -> Void in
		result = baseArray[i]
	}
	return result
}

func getElements(range: Range<Int>) -> [Int] {
	var result = [Int](range)
	dispatch_sync(queue) { () -> Void in
		result = Array(baseArray[range])
	}
	return result
}

let start1 = NSDate()
for _ in 0 ..< 10000 {
	let childArray1 = childArray1Range.map { (i) -> Int in
		return baseArray[i]
	}
	let childArray2 = childArray2Range.map { (i) -> Int in
		return baseArray[i]
	}
}
print(-start1.timeIntervalSinceNow)

let start2 = NSDate()
for _ in 0 ..< 10000 {
	let childArray1 = Array(baseArray[childArray1Range])
	let childArray2 = Array(baseArray[childArray2Range])
}
print(-start2.timeIntervalSinceNow)

let start3 = NSDate()
for _ in 0 ..< 10000 {
	let childArray1 = childArray1Range.map { (i) -> Int in
		return getElement(i)
	}
	let childArray2 = childArray2Range.map { (i) -> Int in
		return getElement(i)
	}
}
print(-start3.timeIntervalSinceNow)

let start4 = NSDate()
for _ in 0 ..< 10000 {
	let childArray1 = getElements(childArray1Range)
	let childArray2 = getElements(childArray2Range)
}
print(-start4.timeIntervalSinceNow)
```

これで、一つのデータ処理専用直列キュー `queue` が一つ作られました。そしてさらにデータの取得にも専用の関数 `getElement(i: Int)` と `getElements(range: Range<Int>)` も用意しておきました。これで割と通常のアプリ制作に近いイメージになるのではないかと思います。本当にアクセスしたい `baseArray` を `private` にすれば、外部から直接アクセスする方法がなくなるので、必ず `getElement` などのメソッドでデータ処理キューを介してアクセスするしかなくなります。これで、
1. `map` で直接データを取る
2. `slice` で直接データを取る
3. `map` でデータキューを介してデータを取る
4. `slice` でデータキューを介してデータを取る
の 4 パターンが作られました。これでもう一回実行してみましょう。すると自分の環境では下記の実行タイムデータが取れました：
0.160254001617432
0.191264986991882
0.994471967220306
0.305835008621216

1 番と 2 番は先ほどのものと同じように、やはり `map` の方がほんのわずか早い結果となりました。ところが気になる 3 番と 4 番では、なんと 4 番の方が 3 番よりはるかに早い結果となりました。スピードで言うと~~シャア専用じゃないのに~~ 3 倍以上です。まあそれでもやはり `dispatch` をかませている以上直接データを取るようにかなり遅い結果となりましたが。

なぜこの結果になったかというと、まあ説明するまでもなく `dispatch` のせいですね。やはり `dispatch` 自体はかなり重い作業のようですので、`map` は要素の数だけ `dispatch` があるのに対し、`slice` は一回の `dispatch` だけで済むわけですから、範囲が広ければ広いほど、`slice` の優位性がより目立つでしょう。

というわけで、適当に配列の一部範囲を取り出して新しい配列を生成する方法のパフォーマンスを比較してみました。皆さんの何か役に立てると嬉しいです。