.mapでbreak処理をするにはどうしたらよいか


Swiftの通常のfor文で、以下のようなコードを書きました。

[code]

    import Foundation
    
    let testArray = [0,1,2,3,4,5]
    var newArray = [Int]()
    for test in testArray
    {
        newArray.append(test*2)
        if test == 4
        {
            break
        }
    }
    print(newArray)
    
[/code]

このコードを実行すると、`[0, 2, 4, 6, 8]`がprintされます。

しかし、for文より.mapのほうが処理速度が早いという記事を読んだので  
これを.mapに書き換えたいと考えています。  
ただ、.mapだとbreak文に相当するものがあるのか分かりません。

以下のようなコードを書いたのですが、breakするにはどうしたら良いでしょうか？  
また、.mapの使用方法にもやや自信がないのですが、このような場合、filterなどを使ったほうが良いのでしょうか？  

[code]

    import Foundation
    
    let testArray = [0,1,2,3,4,5]
    var newArray = [Int]()
    _ = testArray.map
    {
        let test = $0
        newArray.append(test*2)
        if test == 4
        {
            //break
        }
    }
    print(newArray)
    
[/code]




> for文より.mapのほうが処理速度が早いという記事を読んだ

場合によりけりです。for-inを使ったコードを`map`に置き換えれば必ず早くなるとは思わない方がいいでしょう。

> 以下のようなコードを書いたのですが、breakするにはどうしたら良いでしょうか？  
>  また、.mapの使用方法にもやや自信がないのですが、このような場合、filterなどを使ったほうが良いのでしょうか？

Swiftの`map`には途中でのbreakを実現する機能はありません。

たとえば出来るだけ`map`の働きを生かして書こうと思うと、こんな感じになるでしょう。

[code]

        let endIndex = testArray.firstIndex(of: stopValue) ?? testArray.endIndex
        let newArray = testArray[0...endIndex]
            .map {$0 * 2}
    
[/code]

(`stopValue`には、あなたのコードで`4`に相当する値が入っている想定。)

但し、最初に書きましたが、手元でmacOSのCommand Line
Toolプロジェクトとして配列の要素数を1億(停止する要素の位置を4千万番目)とかでRelease設定(最適化が`-O`:速度優先になる)で実行時間を比べてみましたが、どちらかが有意に高速と言う結果は得られませんでした。

[code]

    import Foundation
    
    let testArray = Array(0..<100_000_000)
    let stopValue = 40_000_000
    
    do {
        let start = Date()
        let endIndex = testArray.firstIndex(of: stopValue) ?? testArray.endIndex
        let newArray = testArray[0...endIndex]
            .map {$0 * 2}
        let end = Date()
        print(newArray.count, end.timeIntervalSince(start))
        print(newArray.reduce(0, +))
    }
    
    do {
        let start = Date()
        var newArray = [Int]()
        //newArray.reserveCapacity(testArray.count)
        for test in testArray
        {
            newArray.append(test*2)
            if test == stopValue
            {
                break
            }
        }
        let end = Date()
        print(newArray.count, end.timeIntervalSince(start))
        print(newArray.reduce(0, +))
    }
    
[/code]

私の手元での実行結果

[code]

    40000001 0.18691504001617432
    1600000040000000
    40000001 0.2031090259552002
    1600000040000000
    
[/code]

* * *

「for文より.mapのほうが処理速度が早い」といった単純化されすぎてときに適切ではなくなる「標語」を覚えるのではなく、配列に要素を追加していく処理を繰り返す場合、最初に`reserveCapacity`を呼んでおくと高速化できる、と言った要素を個別に覚えていかれた方が良いでしょう。




> for文より.mapのほうが処理速度が早いという記事を読んだ

場合によりけりです。for-inを使ったコードを`map`に置き換えれば必ず早くなるとは思わない方がいいでしょう。

> 以下のようなコードを書いたのですが、breakするにはどうしたら良いでしょうか？  
>  また、.mapの使用方法にもやや自信がないのですが、このような場合、filterなどを使ったほうが良いのでしょうか？

Swiftの`map`には途中でのbreakを実現する機能はありません。

たとえば出来るだけ`map`の働きを生かして書こうと思うと、こんな感じになるでしょう。

[code]

        let endIndex = testArray.firstIndex(of: stopValue) ?? testArray.endIndex
        let newArray = testArray[0...endIndex]
            .map {$0 * 2}
    
[/code]

(`stopValue`には、あなたのコードで`4`に相当する値が入っている想定。)

但し、最初に書きましたが、手元でmacOSのCommand Line
Toolプロジェクトとして配列の要素数を1億(停止する要素の位置を4千万番目)とかでRelease設定(最適化が`-O`:速度優先になる)で実行時間を比べてみましたが、どちらかが有意に高速と言う結果は得られませんでした。

[code]

    import Foundation
    
    let testArray = Array(0..<100_000_000)
    let stopValue = 40_000_000
    
    do {
        let start = Date()
        let endIndex = testArray.firstIndex(of: stopValue) ?? testArray.endIndex
        let newArray = testArray[0...endIndex]
            .map {$0 * 2}
        let end = Date()
        print(newArray.count, end.timeIntervalSince(start))
        print(newArray.reduce(0, +))
    }
    
    do {
        let start = Date()
        var newArray = [Int]()
        //newArray.reserveCapacity(testArray.count)
        for test in testArray
        {
            newArray.append(test*2)
            if test == stopValue
            {
                break
            }
        }
        let end = Date()
        print(newArray.count, end.timeIntervalSince(start))
        print(newArray.reduce(0, +))
    }
    
[/code]

私の手元での実行結果

[code]

    40000001 0.18691504001617432
    1600000040000000
    40000001 0.2031090259552002
    1600000040000000
    
[/code]

* * *

「for文より.mapのほうが処理速度が早い」といった単純化されすぎてときに適切ではなくなる「標語」を覚えるのではなく、配列に要素を追加していく処理を繰り返す場合、最初に`reserveCapacity`を呼んでおくと高速化できる、と言った要素を個別に覚えていかれた方が良いでしょう。

