【问题标题】:Unify Arrays and Array Slices in Swift在 Swift 中统一数组和数组切片
【发布时间】:2015-07-16 17:01:07
【问题描述】:

我对 Swift 和一般的 Apple 编程非常陌生。我写这段代码是为了进行二分搜索。

func binarySearch<X:Comparable> (needle:X, haystack:[X])->X? {
    if haystack.isEmpty { return nil }
    let mid = haystack.count / 2
    let found = haystack[mid]
    if found == needle {
        return needle
    }
    else if found < needle {
        return binarySearch(needle, haystack[0..<mid])
    }
    else {
        return binarySearch(needle, haystack[mid+1..<haystack.count])
    }
}

我在递归调用中遇到语法错误,因为第二个参数的类型是 ArraySlice&lt;X&gt; 而不是 Array&lt;X&gt;

我通过使用相同的版本重载 binarySearch 来解决这个问题,除了第二个参数的类型是 ArraySlice&lt;X&gt;

我认为如果这一切都可以在一个函数中完成会更优雅。有没有合适的类型可以统一 Array 和 ArraySlice?我尝试使用ArrayLiteralConvertible&lt;X&gt;,但由于某种原因没有计数成员。我仍然很难在文档中找到自己的方式,所以我很容易忽略了更好的选择。

你能提出一个好的方法吗?如果它涉及使用内置类,您能否给我一个提示,告诉我下次如何自己找到它,而不是写信给 SO?

【问题讨论】:

    标签: arrays swift generics


    【解决方案1】:

    要解决最初的问题,请使用切片调用 Array 构造函数以获取数组:

    func binarySearch<X:Comparable> (needle:X, haystack:[X])->X? {
        if haystack.isEmpty { return nil }
        let mid = haystack.count / 2
        let found = haystack[mid]
        if found == needle {
            return needle
        }
        else if needle < found {
            return binarySearch(needle, Array(haystack[0..<mid]))
        }
        else {
            return binarySearch(needle, Array(haystack[mid+1..<haystack.count]))
        }
    }
    

    另外,你的条件应该是if needle &lt; found

    【讨论】:

    • 但是你失去了数组切片的优势,它只是对原始数组的引用。 (如果您从切片创建新数组,了解运行时有多智能以及复制了多少数据会很有趣。)
    • 是的。我想我们会在开源 Swift 发布时找到答案。
    【解决方案2】:

    是的,Array/ArraySlice 很烦人。您需要的基本通用要求在this 问题中有详细说明。但是,为了满足您的要求,不幸的是,您必须获得一些非常可怕的函数签名。不过,这可能的:

    func bSearch<
      S : Sliceable where S.SubSlice : Sliceable,
      S.SubSlice.Generator.Element == S.Generator.Element,
      S.SubSlice.SubSlice == S.SubSlice,
      S.Generator.Element : Comparable,
      S.Index : IntegerArithmeticType,
      S.Index : IntegerLiteralConvertible,
      S.SubSlice.Index == S.Index
      >(el: S.Generator.Element, list: S) -> S.Generator.Element? {
    
        if list.isEmpty { return nil }
    
        let midInd = list.endIndex / 2
    
        let midEl: S.Generator.Element = list[midInd] // type inference giving me some bugs here
    
        if midEl == el {
          return el
        }
    
        return midEl < el ?
          bSearch(el, list: list[midInd+1..<list.endIndex]) :
          bSearch(el, list: list[0..<midInd])
    }
    

    对于 Swift 1.2,只需将正文替换为:

    if isEmpty(list) { return nil }
    
    let midInd = list.endIndex / 2
    
    let midEl: S.Generator.Element = list[midInd] // type inference giving me some bugs here
    
    if midEl == el {
      return el
    }
    
    return midEl < el ?
      bSearch(el, list[midInd+1..<list.endIndex]) :
      bSearch(el, list[0..<midInd])
    

    【讨论】:

    • 不错! – 或许添加这是 Swift 2.0 并且需要 Xcode 7 beta 的信息。
    • 糟糕。你是对的。我会在那里添加它(我可能会开始尝试添加一个 Swift 1.2 版本...)
    • 其实我不喜欢在这里使用 switch/case(使用人为的默认情况来使编译器满意)而不是简单的 if/else if/else。但这是一个品味问题:)
    • 是的,你是对的。我最初把它放在那里是因为编译器发脾气——无论出于什么原因都无法管理 if 语句。
    • 感谢您抽出宝贵时间来做这件事。我同意这很可怕。我会坚持我原来的方法,但我确实打算通过类型规范来工作。
    猜你喜欢
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 2021-09-04
    • 2015-01-29
    • 1970-01-01
    • 2012-09-17
    相关资源
    最近更新 更多