如何在Swift中实现Haskell的splitEvery? [英] How to implement Haskell's splitEvery in Swift?

查看:97
本文介绍了如何在Swift中实现Haskell的splitEvery?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

  let x =(0 ..< 10).splitEvery(3 )
XCTAssertEqual(x,[(0 ... 2),(3 ... 5),(6 ... 8),(9)],破坏的实现)

评论



计算范围内元素数量的问题等等。

 扩展范围
{
func splitEvery (nInEach:Int) - > [范围]
{
let n = self.endIndex - self.startIndex //错误 - 无法用类型(T,T)的参数列表调用' - '

}


解决方案

范围中的值是 ForwardIndexType ,所以你只能 advance()它们,
或计算距离( ),但是减法 - 未定义。提前金额必须是相应的
类型 T.Distance 。所以这可能是一个可能的实现:

 扩展范围{
func splitEvery(nInEach:T.Distance) - > ; [范围] {
var result = [Range]()//从空数组开始
var from = self.startIndex
!from!= self.endIndex {
//前进位置,但不超出最终指数:
let to = advance(from,nInEach,self.endIndex)
result.append(from ..< to)
//继续下一间隔:
从=到
}
返回结果
}
}

示例:

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

请注意, 0 ..< 10 不是整数列表(或数组)。要将数组拆分为子数组,可以定义一个类似的扩展名:

 扩展数组{
func splitEvery(nInEach:Int) - > [[T]] {
var result = [[T]]()
for stride(from:0,to:self.count,by:nInEach){
let to = array(self [from ..< to]))
}
返回结果
} $ b = advance(from,nInEach,self.count)
result.append
$ b $ / code>

示例:

//输出:[[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
from!= seq.endIndex {
let = advance(from,nInEach,seq.endIndex)
result.append(seq [from ..< to])
from = to
}
返回结果

$ / code>

(请注意,这个函数完全无关)



示例:

pre> println(splitEvery(abcdefg,2))
//输出:[ab,cd,ef,g]
println(splitEvery([3.1,
//输出:[[3.1,4.1],[5.9,2.6],[5.3]]
pre>

范围不是可分割的,但您可以定义一个单独的函数,它需要
范围参数:

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

var from = range.startIndex
from!= range.endIndex {
let = advance(from,nInEach,range.endIndex)
result.append(from ..< to)
from = to
}
返回结果

示例:

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


PROBLEM

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

COMMENTS

I am running into problems calculating number of elements in the Range, etc...

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

解决方案

The values in a range are of ForwardIndexType, so you can only advance() them, or compute the distance(), but the subtraction - is not defined. The advance amount has to be of the corresponding type T.Distance. So this would be a possible implementation:

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

Example:

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

Note however that 0 ..< 10 is not a list (or array) of integers. To split an array into subarrays you could define a similar extension:

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

Example:

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

A more general approach could be to split all sliceable objects. But Sliceable is protocol and protocols cannot be extended. What you can do instead is to define a function that takes the sliceable object as the first argument:

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
}

(Note that this function is completely unrelated to the (extension) methods defined above.)

Example:

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

Ranges are not sliceable, but you could define a separate function that takes a range argument:

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
}

Example:

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

这篇关于如何在Swift中实现Haskell的splitEvery?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆