2014-11-01 2 views
3

ПРОБЛЕМАКак реализовать раскол Haskell в Swift?

let x = (0..<10).splitEvery(3) 
XCTAssertEqual(x, [(0...2),(3...5),(6...8),(9)], "implementation broken") 

КОММЕНТАРИИ

Я бегу в проблемы вычисления числа элементов в диапазоне, и т.д ...

extension Range 
{ 
    func splitEvery(nInEach: Int) -> [Range] 
    { 
     let n = self.endIndex - self.startIndex // ERROR - cannot invoke '-' with an argument list of type (T,T) 
    } 
} 

ответ

5

Значения в диапазоне являются ForwardIndexType, поэтому вы можете только advance() их, или вычислить distance(), но вычитание - не определено. Сумма аванса должна быть соответствующей типа T.Distance. Так что это было бы возможным осуществление:

extension Range { 
    func splitEvery(nInEach: T.Distance) -> [Range] { 
     var result = [Range]() // Start with empty array 
     var from = self.startIndex 
     while from != self.endIndex { 
      // Advance position, but not beyond the end index: 
      let to = advance(from, nInEach, self.endIndex) 
      result.append(from ..< to) 
      // Continue with next interval: 
      from = to 
     } 
     return result 
    } 
} 

Пример:

println((0 ..< 10).splitEvery(3)) 
// Output: [0..<3, 3..<6, 6..<9, 9..<10] 

Однако обратите внимание, что 0 ..< 10 не список (или массив) целых чисел. Для того, чтобы разбить массив в подмассивов можно определить аналогичное расширение:

extension Array { 
    func splitEvery(nInEach: Int) -> [[T]] { 
     var result = [[T]]() 
     for from in stride(from: 0, to: self.count, by: nInEach) { 
      let to = advance(from, nInEach, self.count) 
      result.append(Array(self[from ..< to])) 
     } 
     return result 
    } 
} 

Пример:

println([1, 1, 2, 3, 5, 8, 13].splitEvery(3)) 
// Output: [[1, 1, 2], [3, 5, 8], [13]] 

Более общий подход может быть, чтобы разделить все sliceable объектов. Но Sliceable is протокол и протоколы не могут быть расширены. Что вы можете сделать вместо этого, чтобы определить функции, которая принимает sliceable объекта в качестве первого аргумента:

func splitEvery<S : Sliceable>(seq : S, nInEach : S.Index.Distance) -> [S.SubSlice] { 
    var result : [S.SubSlice] = [] 

    var from = seq.startIndex 
    while from != seq.endIndex { 
     let to = advance(from, nInEach, seq.endIndex) 
     result.append(seq[from ..< to]) 
     from = to 
    } 
    return result 
} 

(Обратите внимание, что эта функция не имеет никакого отношения к (расширения) методов определены выше)

Пример:.

println(splitEvery("abcdefg", 2)) 
// Output: [ab, cd, ef, g] 
println(splitEvery([3.1, 4.1, 5.9, 2.6, 5.3], 2)) 
// Output: [[3.1, 4.1], [5.9, 2.6], [5.3]] 

Диапазоны повторно не sliceable, но вы могли бы определить отдельную функцию, которая принимает аргумент диапазона а:

func splitEvery<T>(range : Range<T>, nInEach : T.Distance) -> [Range<T>] { 
    var result : [Range<T>] = [] 

    var from = range.startIndex 
    while from != range.endIndex { 
     let to = advance(from, nInEach, range.endIndex) 
     result.append(from ..< to) 
     from = to 
    } 
    return result 
} 

Пример:

println(splitEvery(0 ..< 10, 3)) 
// Output: [0..<3, 3..<6, 6..<9, 9..<10] 
+0

Глуховского - родовое реализацию! – kfmfe04

+0

странно, это прекрасно работает на Playground, но у меня возникают проблемы с его компиляцией в проекте. Я разместил здесь новую запись: http://stackoverflow.com/q/26694296/975129 – kfmfe04

+0

@ kfmfe04: У меня есть немного расширил ответ. Дайте мне знать, если вам нужна дополнительная информация. –

Смежные вопросы