簡體   English   中英

如何在Swift中實現Haskell的splitEvery?

[英]How to implement Haskell's splitEvery in Swift?

問題

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

評論

我在計算Range等元素數量時遇到問題......

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

在一個范圍內的值是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協議 ,協議無法擴展。 你可以做的反而是定義一個函數 ,它的可切片的對象作為第一個參數:

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]]

范圍不可切片,但您可以定義一個帶范圍參數的單獨函數:

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]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM