1

基本的に次のようなコードがあります。

func arrayHalvesEqual(data:[UInt8]) -> Bool {
    let midPoint = data.count / 2
    for i in 0..<midPoint {
        let b = data[i]
        let b2 = data[i + midPoint]
        if b != b2 {
            return false
        }
    }
    return true
}

これは問題なく動作しますが、配列を渡したい場合もあれば、ArraySlice を渡したい場合もあります。CollectionType次のように変換されるジェネリックとプロトコルを使用するように変更すると思いました。

func arrayHalvesEqual<ByteArray : CollectionType where ByteArray.Generator.Element == UInt8>(data:ByteArray) -> Bool {
    let midPoint = data.count / 2
    for i in 0..<midPoint {
        let b = data[i]
        let b2 = data[i + midPoint]
        if b != b2 {
            return false
        }
    }
    return true
}

ただし、次のコンパイラ エラーが発生します。

error: binary operator '..<' cannot be applied to operands of type 'Int' and 'ByteArray.Index.Distance'
    for i in 0..<midPoint {

そのコンパイルを行うfor ループを切り替えることはできますが、data.indices は抽象を返すのに対し、/ 2 は Int であるfor i in data.indicesため、これを 2 で割って midPoint を取得することはできなくなります。CollectionType.Index

Swiftでこのようなことをすることは可能ですか? 抽象プロトコルのインデックス型と、数学を実行できる実際の型との間を橋渡しできますか?

indicesPS: andを使用してコレクション全体を反復する他の例を見て見つけましたenumerateが、コレクションの半分を明示的に反復したいだけで、ある種の 2 による除算が必要です。

ありがとう

4

1 に答える 1

1

によってインデックス付けされたコレクションにメソッドを制限できますInt

func arrayHalvesEqual<ByteArray : CollectionType where ByteArray.Index == Int, ByteArray.Generator.Element == UInt8>
    (data:ByteArray) -> Bool { ... }

これは と の両方ArrayをカバーしArraySliceます。

indices.startIndexまた、初期インデックスとしての代わりに使用する場合は0、インデックス タイプを に制限するだけで十分IntegerTypeです。また、データ型UInt8はジェネリックに置き換えることができEquatable、メソッド全体は次のように短縮されます

func arrayHalvesEqual<ByteArray : CollectionType where ByteArray.Index : IntegerType, ByteArray.SubSequence.Generator.Element : Equatable>
    (data:ByteArray) -> Bool {

        let midPoint = (data.indices.endIndex - data.indices.startIndex)/2
        let firstHalf = data[data.indices.startIndex ..< midPoint]
        let secondHalf = data[midPoint ..< data.indices.endIndex]
        return !zip(firstHalf, secondHalf).contains { $0 != $1 }
}
于 2016-02-18T02:27:24.553 に答える