对[Any]数组进行排序

Luc*_*tti 13 arrays sorting generics introspection swift

给定一个数组定义如下

let list: [Any]
Run Code Online (Sandbox Code Playgroud)

我想将其排序WHEN

  1. 其中的所有值都具有相同的类型 Element
  2. ElementComparable.

什么时候应该返回排序的数组

所以我需要一个函数,当数组以类似下面的方式填充时

let list: [Any] = [10, 11, 0, 2, -1]
let list: [Any] = ["Red", "Green", "Blue"]
let list: [Any] = [true, false, true, true]
Run Code Online (Sandbox Code Playgroud)

确实返回排序的数组.

什么时候应该返回零

另一方面,当list包含以下示例之一时

let list: [Any] = [CGPointZero, CGPoint(x:1, y:1)] // CGPoint is not comparable
let list: [Any] = [10, "Hello"] // Values of different types
Run Code Online (Sandbox Code Playgroud)

我想要nil作为回报值.

任何的想法?

JMI*_*JMI 6

编译时间解决方案

extension _ArrayType where Generator.Element == Any {
    func sortQ() -> Any? {
        return nil
    }
}

extension _ArrayType where Generator.Element: Comparable {
    func sortQ() -> [Self.Generator.Element] {
        return self.sort(<)
    }
}

// Because Bool is not comparable by default...
extension Bool: Comparable {
}

public func < (lhs: Bool, rhs: Bool) -> Bool {
    return !lhs && rhs // or Int(lhs) < Int(rhs)
}

[10, 11, 0, 2, -1].sortQ()               //[-1, 0, 2, 10, 11]
["Red", "Green", "Blue"].sortQ()         //["Blue", "Green", "Red"]
[true, false, true, true].sortQ()        //[false, true, true, true]
[CGPointZero, CGPoint(x:1, y:1)].sortQ() //nil
[10, "Hello"].sortQ()                    //nil
Run Code Online (Sandbox Code Playgroud)

运行时解决方案:

UPDATE

这是非最终状态.问题在于铸造具有可比性.恕我直言,这是不可能的.到目前为止,我还不知道有关可选类型的技巧.无论如何,甚至不能转换元类型,因为直到运行时才知道类型.我的弱解决方法是列出支持的可比类型:

extension _ArrayType {

    func sortQ() -> [Generator.Element]? {
        var arrayOK = true
        let sortedArray = sort { (firstElement, secondElement) -> Bool in
            guard arrayOK else {
                return false
            }

            let f = Mirror(reflecting: firstElement)
            let s = Mirror(reflecting: secondElement)

            guard f.subjectType == s.subjectType else {
                arrayOK = false
                return false
            }

            switch String(f.subjectType) {
            case "Int":
                return (firstElement as! Int) < (secondElement as! Int)
            case "String":
                return (firstElement as! String) < (secondElement as! String)
            case "Bool":
                return (firstElement as! Bool) < (secondElement as! Bool)
            default:
                arrayOK = false
                return false
            }
        }
        return arrayOK ? sortedArray : nil
    }
}
Run Code Online (Sandbox Code Playgroud)

更新2

第二种选择是以不同的方式定义可比较的协议(AnyComparable).不幸的是,它意味着为所有可比类型创建扩展.否则,在编译时,编译器无法找到正确的函数/运算符(因为它不会提前知道类型).

所以你有两个选择:

  1. 如果您对比较的类型有所了解并明确定义它们(更新1).
  2. 使用不使用Self类型的接口(更新2).

恕我直言,没有其他解决方案

protocol AnyComparable {
    func compareTo(second: Any) -> Bool 
}

extension AnyComparable where Self: Comparable {
    func compareTo(second: Any) -> Bool {
        if let secondSameType = second as? Self {
            return self < secondSameType
        }

        return false
    }
}

extension Int: AnyComparable {
}

extension String: AnyComparable {
}

extension Bool: AnyComparable {
}

extension _ArrayType {

    func sortQ() -> [Generator.Element]? {

        var arrayOK = true
        var wantedType: Any.Type?

        let sortedArray = sort { (firstElement, secondElement) -> Bool in
            guard arrayOK else {
                return false
            }

            if wantedType == nil {
                wantedType = Mirror(reflecting: firstElement).subjectType
            }

            guard let f = firstElement as? AnyComparable where wantedType == Mirror(reflecting: secondElement).subjectType else {
                arrayOK = false
                return false
            }

            return f.compareTo(secondElement)
        }
        return arrayOK ? sortedArray : nil
    }
}
Run Code Online (Sandbox Code Playgroud)


Jos*_*reu 5

目前,我写了一个小扩展来检查所有元素是否属于同一类型(我将在此处检查是否可以获得结果):

extension _ArrayType where Generator.Element == Any{

    func hasEqualTypeAndComparable()->Bool{

        if self.count > 0{
            let firstType = self.first?.dynamicType

            for val in self{
                if firstType != val.dynamicType{
                    return false
                }
            }

            return self.first is Comparable
        }

        return false
    }

}
Run Code Online (Sandbox Code Playgroud)

例:

//Example 1 
var values:[Any] = [2,1,4,3,"Hola"]
values.hasEqualTypeAndComparable() // Print false

//Example 2
var values:[Any] = [2,1,4,3]
values.hasEqualTypeAndComparable() // Prints true
Run Code Online (Sandbox Code Playgroud)