当前位置: 首页 > 面试题库 >

如何在Swift中实现Haskell的splitEvery?

蓬祺
2023-03-14
问题内容

问题

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

问题答案:

范围中的值是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]]

范围是不可切片的,但是您可以定义一个带有range参数的单独函数:

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]


 类似资料:
  • 问题内容: 我正在使用iOS的Google Maps API,并想使用标记聚类实用程序。我想出了如何显示聚簇标记,但是我想自定义标记。有人可以解释如何设置/更改每个标记或群集标记的图标和标题吗?示例代码将非常有帮助。 到目前为止,这就是我所拥有的。我不知道该如何处理renderClusters和更新函数。 问题答案: 在 Swift 4上 ,我找到了一种针对聚簇标记的干净解决方案,可以为聚簇使用自

  • 我是斯威夫特编程新手,请告诉我如何用代码在斯威夫特实现单例类。 在obj-c中我知道 斯威夫特怎么样

  • 问题内容: 如何在 Swift 3.0中 实现方法混乱? 我已经阅读了有关nshipster的文章,但是在这段代码中 编译器给我一个错误 在Swift中不可用dispatch_once_t:而是使用延迟初始化的全局变量 问题答案: 首先,在Swift 3.0中不可用。您可以选择两种选择: 全局变量 静态财产,或 令人毛骨悚然的CocoaTouch类,例如UIViewController; 定制的S

  • 问题内容: 这是推特的一些代码和平…我想知道如何像在iOS堆栈照片应用程序中一样获得共享操作视图… 问题答案:

  • 问题内容: 我已经在Swift中实现了一个使用字典键的Set。我想实现一个addAll(sequence)方法,该方法在Set中的Elements上采用任何序列类型,但是出现一个没有意义的错误。这是我的代码 我在XCode 6.1和6.0.1中遇到此错误。 我想遵循Array的extend方法的语义,但是该类型签名甚至不为我编译。 我做错了什么,还是应该提交雷达? 编辑 :刚刚找到https://

  • 我正在尝试使用Flutter编写移动应用程序。不幸的是,我需要实现一个Flutter插件才能调用一些原生API。 Objective-C对我来说太陌生了,所以我真的更喜欢使用Swift(我也不太了解,但它离Kotlin很近,我觉得很熟悉)来创建插件。 我通过Flatter获得了插件框架设置,但现在我正在尝试实现方法处理函数: 我尝试使用的本机函数具有以下签名(使用gomobile生成): 但有几件