简单的 Swift 数组扩展

Posted

技术标签:

【中文标题】简单的 Swift 数组扩展【英文标题】:Simple Swift Array Extension 【发布时间】:2015-03-16 00:17:44 【问题描述】:

尝试扩展 Array 类型以使用二进制排序来按顺序插入元素。 这是我的游乐场代码:

  extension Array  

      func insertionIndexOf(elem: T , isOrderedBefore: (T, T) -> Bool) -> Int 
       var lo = 0
       var hi = self.count - 1
       while lo <= hi 
        let mid = (lo + hi)/2
        if isOrderedBefore(self[mid], elem) 
            lo = mid + 1
         else if isOrderedBefore(elem, self[mid]) 
            hi = mid - 1
         else 
            return mid
        
    
        return 0 
 


  mutating func insertOrdered(elem: T)
     let index = self.insertionIndexOf(elem, isOrderedBefore:  (a , b)     in return (a > b)  )
     return insert(elem, atIndex: index)

我得到一个编译器错误:“不能调用带有类型参数列表的insertionIndexOf (T, isOrderedBefore: (_, _) -> _)”

奇怪的是,如果我改用:

    mutating func insertOrdered(elem: T)
         let index = self.insertionIndexOf(elem, isOrderedBefore:  (a , b) in return false  )
         return insert(elem, atIndex: index)
        

编译器平静下来,但数组插入不会被排序,:(当然。 请问有什么想法吗??谢谢。

(使用 Xcode 6.3 beta 2 - Swift 1.2)

【问题讨论】:

那段代码看起来很眼熟***.com/a/26679191/1187415 :) – 注意最后的return 0 应该是return lo @MartinR 是的 :) 我使用您的示例进行二分搜索,以便为我的问题添加上下文。我一直在玩扩展名。抱歉,刚刚忘记添加指向您的代码的链接。希望没有伤害。 @MartinR ***.com/questions/29107928/… 【参考方案1】:

从 Swift 2 开始,这可以通过协议扩展方法来实现:

extension CollectionType where Generator.Element : Comparable, Index == Int 

    func insertionIndexOf(elem: Generator.Element) -> Int 
        var lo = 0
        var hi = self.count - 1
        while lo <= hi 
            let mid = (lo + hi)/2
            if self[mid] < elem 
                lo = mid + 1
             else if elem < self[mid] 
                hi = mid - 1
             else 
                return mid // found at position mid
            
        
        return lo // not found, would be inserted at position lo
    


extension RangeReplaceableCollectionType where Generator.Element : Comparable, Index == Int 

    mutating func insertOrdered(elem: Generator.Element) 
        let index = self.insertionIndexOf(elem)
        self.insert(elem, atIndex: index)
    

例子:

var ar = [1, 3, 5, 7]
ar.insertOrdered(6)
print(ar) // [1, 3, 5, 6, 7]

这些方法不是直接为struct Array定义的,而是为一些 Array 符合的协议,并提供了必要的 方法。

对于第一种方法,即CollectionType,因为 提供(读取)下标访问,以及集合元素 类型必须是Comparable

第二种方法变异 集合,这里是更严格的协议 RangeReplaceableCollectionType 为必填项。

【讨论】:

【参考方案2】:

您正在尝试评估a &gt; b,但T 可能不是Comparable。今天不可能写出这样的扩展。你想说的是:

extension Array where T: Comparable 

但目前这在 Swift 中是不可能的。编译器团队已经表示这是一个优先事项,但我们不知道它什么时候会涉及到 Swift。

你最好的方法是让它成为一个函数:

func insertOrdered<T: Comparable>(inout xs: [T], x: T)

或者创建一个具有数组的新对象:

struct OrderedArray<T: Comparable> : ... 
    var values: [T]
    func insertionIndexOf(elem: T , isOrderedBefore: (T, T) -> Bool) -> Int
    mutating func inserOrdered(elem: T)
    ...

【讨论】:

感谢一百万个罗伯!我会试试你的建议

以上是关于简单的 Swift 数组扩展的主要内容,如果未能解决你的问题,请参考以下文章

swift 可等于协议的数组扩展

Swift 中的 Array 扩展以使用 NSPropertyListReadOptions 从 plist 中读取数组

如何向 Swift 数组添加扩展以有条件地追加?

替换数组中的多次出现 - Swift 4.1

swift中数组操作

Swift泛型和扩展需要锻炼[重复]