Подтвердить что ты не робот

Сортировка массива [Any]

Учитывая массив, определенный следующим образом:

let list: [Any]

Я хочу отсортировать его КОГДА

  • все значения внутри него имеют один и тот же тип Element
  • И Element есть Comparable.

Когда он должен вернуть отсортированный массив

Поэтому мне понадобится функция, когда массив заполняется таким образом, как следующие

let list: [Any] = [10, 11, 0, 2, -1]
let list: [Any] = ["Red", "Green", "Blue"]
let list: [Any] = [true, false, true, true]

возвращает отсортированный массив.

Когда он должен вернуть nil

С другой стороны, когда list содержит один из следующих примеров

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

Я хочу nil как возвращаемое значение.

Любая идея?

4b9b3361

Ответ 1

Решение времени компиляции

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

Решения времени выполнения:

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

ОБНОВЛЕНИЕ 2

Второй вариант - иметь сопоставимый протокол, определенный по-разному (AnyComparable). К сожалению, это означает создание расширений для всех типов Comparable. Иначе нет способа, во время компиляции компилятор может найти правильную функцию/оператор (поскольку он не знает типы раньше времени).

Итак, у вас есть два варианта:

  • если у вас есть представление о типах, которые вы сравнивали и определяете их явно (обновление 1).
  • Использовать интерфейс, который не использует Self тип (обновление 2).

IMHO нет другого решения

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

Ответ 2

На данный момент я написал небольшое расширение, чтобы проверить, имеют ли все элементы одного типа (я буду работать над этим, чтобы проверить, может ли он получить результат):

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
    }

}

Пример:

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

Ответ 3

Если ваш прецедент позволяет вам дать подсказку компилятору, вы можете указать фильтр по типу вывода, который вы хотите:

extension _ArrayType where Generator.Element == Any {

    func filterByType<T: Comparable>() -> [T] {

        var output = [T]()

        for i in self {
            if let j = i as? T {
                output.append(j)
            }
        }

        return output
    }
}

Если входной массив не содержит элементов указанного типа, он просто вернет пустой массив. Если тип не является сравнимым, тогда код не будет компилироваться.

Пример:

let list: [Any] = [10, "Hello", 3, false, "Foo", "Bar", 1] // Values of different types

var output = list.filterByType() as [Int]
output.sortInPlace()

Ответ 4

extension Array{

func wtCompare()->[Any]?{
    if self.count>0 {
        let first = self.first.dynamicType

        for obj in self{
            if obj is Comparable {
                if first.dynamicType != obj.dynamicType {
                    return nil
                }
            }else{
                return nil
            }
        }
        let sorted = self.sorted { (a, b) -> Bool in
            return a < b
        }
        return sorted
    }else{
        return nil
    }
    return nil
}}