Сортировка массива [Любой]

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

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]

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

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

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

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

я хочуnil в качестве возвращаемого значения.

Любая идея?

 Luca Angeletti01 июл. 2016 г., 23:00
@dfri: да, я пытался конвертироватьlist в[Element] используя этоlet casted = list.flatMap { $0 as? list.first!.dynamicType } но компилятору это не нравится
 pacification01 июл. 2016 г., 22:14
@appzYourLife так, что типElement?
 Luca Angeletti01 июл. 2016 г., 22:12
@shim: я не нашел ничего, что работает
 Luca Angeletti01 июл. 2016 г., 22:15
@pacification: любой тип действительно. Это просто должно бытьComparable, Приведенные мной примеры должны прояснить концепцию.
 shim01 июл. 2016 г., 22:27
Есть ли подмножество типов, которые на самом деле будет содержать ваш массив? (например, будет содержать только строки, числа или bools)? Или никаких ограничений вообще?
 dfri01 июл. 2016 г., 23:04
Я полагаю, что это определенное ограничение («недостаток») статической типизации / безопасности типов, которым славится Swift. Возможно, вы могли бы несколько обойти это, используя методы Obj-C и самоанализ во время выполнения, но, если возможно, я подозреваю, что это ограничит вас проверкойComparableколичество ссылочных типов (по Obj-C KVO) с помощьюNSObject класс-оболочка подкласса дляList, но только чтение этого предложения снова освещает беспорядок этого ... :)
 dfri01 июл. 2016 г., 22:57
Сложность в том, что Swift не может знать, если значение «обернуто»Any сопоставим (см.например этот смысл) безсначала выполняется попытка преобразования типа в конкретный тип и после этого - при условии успешного сравнения - проверка того, является ли этот типComparable или нет. Это означает, что вы можете решить эту сортировкуесли Вы в то же время предоставили тип «завернутый»Any, но я предполагаю, что это устраняет всю цель общей сортировки, как указано выше.
 Luca Angeletti01 июл. 2016 г., 22:37
@shim: нет ограничений.

Ответы на вопрос(4)

у, вы можете указать фильтр по типу вывода, который вы хотите:

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

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

Пример:

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

var output = list.filterByType() as [Int]
output.sortInPlace()
 Luca Angeletti10 июл. 2016 г., 17:27
Спасибо за ваш ответ. К сожалению, тип элементов внутри массива неизвестен. Это может быть любой тип.

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

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
 Luca Angeletti01 июл. 2016 г., 22:52
Очень хороший первый шаг.
 José Roberto Abreu01 июл. 2016 г., 23:16
Закрытие также не работает для меня. Ммм @dfri Я также проверяю, возвращает false для Comparable (проблема в этой строке), я проверю.
 Luca Angeletti01 июл. 2016 г., 23:03
Хорошо, я видел ваше обновление. Теперь мы можем знать, все ли значения имеют одинаковый тип и сравнимы ли они. Хорошо. Но как мы на самом деле сравниваем их в роде?
 José Roberto Abreu01 июл. 2016 г., 22:54
Кажется, что мы можем проверить, соответствует ли dynamicType сопоставимому протоколу.
 José Roberto Abreu01 июл. 2016 г., 23:27
Я изменяю оператор возврата, который я проверял, теперь возвращаю ожидаемое значение.
 Hamish01 июл. 2016 г., 23:30
Ха ... когда сравниваемый тип не является обязательным (т.е.self.first! is Comparable), то компилятор выдает ошибку,Comparable не может быть использован, так как имеет собственные требования. Интересно, почему это работает с опциями?
 dfri01 июл. 2016 г., 23:36
@ originaluser2 СComparable является неоднородным, я бы предположил, что значение, заключенное в необязательный (.Some<T> или же.None) рассматривается как универсальный, и в этом случае разрешается проверка типа сis Comparable, очень похоже на использованиеComparable как ограничение типа (..<T: Comparable>), где конкретное развернутое значение, естественно, не является общим, что приводит к ошибке времени компиляции.
 dfri02 июл. 2016 г., 00:28
@ originaluser2 Да, действительно странно. Я суммировал эти моменты вэтот смыслЯ мог бы также написать вопрос об этом, если я не могу найти какое-то объяснение этому где-то. Но сейчас спать!
 Sulthan03 июл. 2016 г., 16:18
Это не будет работать в целом. Вы не можете просто сравнивать типы на равенство, потому что они полностью порвутся с подклассами.
 dfri02 июл. 2016 г., 14:11
@ originaluser2 FYI: опубликовал вопрос на эту темуВот; надеюсь, кто-то может пролить свет на это.
 Hamish02 июл. 2016 г., 00:09
@dfri Хм ... хотяis Comparable в этом случае действительно следует сравнитьOptional<T> сам являетсяComparable (что это не напрямую) - а не просто еслиT являетсяComparable, Хотя это, как говорится, похоже, это именно то, что он делает, выглядит как особый случай дляOptional поскольку я не могу воспроизвести это с другими родовыми типами. Очень интересно.
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
}}
 Luca Angeletti12 июл. 2016 г., 12:21
Спасибо за ваш ответ, но этот код не компилируется.
 ayaio12 июл. 2016 г., 12:11
Пожалуйста, прекратите публиковать новые ответы после удаления предыдущего, который вы опубликовали!редактировать ваш уже опубликовал один вместо.

Время компиляции

    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

Runtime-решения:

ОБНОВИТЬ

Здесь не окончательное состояние. Проблема с приведением к сопоставимым. ИМХО это не возможно. До сих пор я не знал о трюке с дополнительным типом. В любом случае даже приведение метатипа невозможно, потому что тип не известен до времени выполнения. Мой слабый способ - перечислить поддерживаемые сопоставимые типы:

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). К сожалению, это означает создание расширений для всех сопоставимых типов. Иначе нет способа, во время компиляции, компилятор может найти правильную функцию / оператор (так как он не знает типы заранее).

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

если у вас есть представление о типах, которые вы сравниваете, и определите их явно (обновление 1).Используйте интерфейс, который не использует тип 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
    }
}
 JMI13 июл. 2016 г., 23:31
@appzYourLife Вы используете swift 2.3 или 3? Какую ошибку вы получили?
 JMI13 июл. 2016 г., 23:51
@appzYourLife Смотрите мое обновление 2. Это невозможно во время выполнения ... Вам придется как-то помочь компилятору ...
 JMI13 июл. 2016 г., 17:45
Ааааа ... Теперь я знаю, что происходит. Вы имели в виду проверку во время выполнения, а не один компилятор. Смотрите мой обновленный ответ.
 Luca Angeletti13 июл. 2016 г., 22:55
@JMI: обновление не компилируется. Во всяком случае есть другиеComparable(s) типы, которые не поддерживаются вашим расширением. Это должно работать с любым типом.
 Luca Angeletti13 июл. 2016 г., 23:49
@JMI: Извините, я пропустил расширение, чтобы сделать Bool Comparable. Но похоже, что этот код работает только для массивов String, Bool и Int. Мне нужно решение для каждого массиваComparable(s) как указано в моем вопросе. Однако, спасибо за попытку найти решение. Я оценил это.
 Luca Angeletti13 июл. 2016 г., 23:52
@JMI: Я согласен, я также считаю, что это невозможно.
 Luca Angeletti13 июл. 2016 г., 23:53
@JMI: у тебя есть мой голос в любом случае

Ваш ответ на вопрос