Swift: Сортировка массива по дескрипторам сортировки

Я использую coredata, поэтому мне нужны дескрипторы сортировки для моих сущностей

Например, объект Coordinate имеет этот класс func:

class func sortDescriptors() -> Array<NSSortDescriptor>
{
    return [NSSortDescriptor(key: "sequence", ascending: true)]
}

Я использую это при выполнении запросов на выборку в CoreData следующим образом:

var request = NSFetchRequest(entityName: entityName)

request.sortDescriptors = T.sortDescriptors()

Однако, когда у меня есть массив координат как свойство на другом объекте coredata, это NSSet (I.e. unsorted)

Чтобы решить эту проблему, я возвращаю координаты следующим образом:

return NSArray(array: coordinates!).sortedArrayUsingDescriptors(Coordinate.sortDescriptors()) as? Array<Coordinate>

Что кажется уродливым, чтобы использовать NSArray только для того, чтобы получить метод sortedArrayUsingDescriptors. Есть ли аналогичный способ сделать это непосредственно на Swift-массиве, I.e. Array<Coordinate> с помощью дескрипторов сортировки?

Спасибо!

Ответ 1

Для этого нет встроенного метода, но вы можете добавить их с помощью расширения протокола:

extension MutableCollectionType where Index : RandomAccessIndexType, Generator.Element : AnyObject {
    /// Sort `self` in-place using criteria stored in a NSSortDescriptors array
    public mutating func sortInPlace(sortDescriptors theSortDescs: [NSSortDescriptor]) {
        sortInPlace {
            for sortDesc in theSortDescs {
                switch sortDesc.compareObject($0, toObject: $1) {
                case .OrderedAscending: return true
                case .OrderedDescending: return false
                case .OrderedSame: continue
                }
            }
            return false
        }
    }
}

extension SequenceType where Generator.Element : AnyObject {
    /// Return an `Array` containing the sorted elements of `source`
    /// using criteria stored in a NSSortDescriptors array.
    @warn_unused_result
    public func sort(sortDescriptors theSortDescs: [NSSortDescriptor]) -> [Self.Generator.Element] {
        return sort {
            for sortDesc in theSortDescs {
                switch sortDesc.compareObject($0, toObject: $1) {
                case .OrderedAscending: return true
                case .OrderedDescending: return false
                case .OrderedSame: continue
                }
            }
            return false
        }
    }
}

Но обратите внимание, что это будет работать только тогда, когда элементы массива являются классами, а не структурами, поскольку метод NSSortDescriptor compareObject требует аргументов, соответствующих AnyObject

Ответ 2

Другим подходом к хорошим расширениям Damien может быть мультилитный.

myArray = (myArray as NSArray).sortedArrayUsingDescriptors(tableView.sortDescriptors) as! Array

Исходный источник: NSHipster

Ответ 3

Swift 3 Версия ответа @Darniel

extension MutableCollection where Self : RandomAccessCollection {
    /// Sort `self` in-place using criteria stored in a NSSortDescriptors array
    public mutating func sort(sortDescriptors theSortDescs: [NSSortDescriptor]) {
        sort { by:
            for sortDesc in theSortDescs {
                switch sortDesc.compare($0, to: $1) {
                case .orderedAscending: return true
                case .orderedDescending: return false
                case .orderedSame: continue
                }
            }
            return false
        }

    }
}

extension Sequence where Iterator.Element : AnyObject {
    /// Return an `Array` containing the sorted elements of `source`
    /// using criteria stored in a NSSortDescriptors array.

    public func sorted(sortDescriptors theSortDescs: [NSSortDescriptor]) -> [Self.Iterator.Element] {
        return sorted {
            for sortDesc in theSortDescs {
                switch sortDesc.compare($0, to: $1) {
                case .orderedAscending: return true
                case .orderedDescending: return false
                case .orderedSame: continue
                }
            }
            return false
        }
    }
}