2016-02-18 3 views
1

У меня есть код, который в основном так:Index и перебрать CollectionType в быстрой

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 i in data.indices, который делает эту компиляцию, но тогда я больше не могу ее разделить на 2, чтобы получить середину, так как data.indices возвращает абстрактный CollectionType.Index, тогда как/2 - Int.

Возможно ли сделать что-то подобное в Swift? Могу ли я соединиться между абстрактным протоколом Тип индекса и некоторый реальный тип, на котором я могу делать математику?

PS: Я видел и нашел другие примеры для итерации по всей коллекции с помощью indices и enumerate, но я явно только хочу перебрать половину коллекции, которая требует своего рода деление на 2

Спасибо

ответ

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 } 
} 
Смежные вопросы