Swift как сортировать массив пользовательских объектов по значению свойства

допустим, у нас есть пользовательский класс с именем imageFile и этот класс содержит два свойства.

class imageFile  {
    var fileName = String()
    var fileID = Int()
}

многие из них хранятся в массиве

var images : Array = []

var aImage = imageFile()
aImage.fileName = "image1.png"
aImage.fileID = 101
images.append(aImage)

aImage = imageFile()
aImage.fileName = "image1.png"
aImage.fileID = 202
images.append(aImage)

вопрос: как я могу сортировать массив изображений по' fileID ' ASC или DESC?

15 ответов


во-первых, объявите свой массив как типизированный массив, чтобы вы могли вызывать методы при итерации:

var images : [imageFile] = []

затем вы можете просто сделать:

Swift 2

images.sorted({ .fileID > .fileID })

Swift 3 & 4

images.sorted(by: { .fileID > .fileID })

приведенный выше пример дает desc порядок


[обновлено для Swift 3 с сортировкой (по:)] это, используя трейлинг-закрытие:

images.sorted { .fileID < .fileID }

где вы используете < или > в зависимости от ASC или DESC, соответственно. если вы хотите изменить элемент images массив, затем используйте следующее:

images.sort { .fileID < .fileID }

если вы собираетесь делать это неоднократно и предпочитаете определять функцию, один из способов:

func sorterForFileIDASC(this:imageFile, that:imageFile) -> Bool {
  return this.fileID > that.fileID
}

и затем использовать как:

images.sort(by: sorterForFileIDASC)

почти все как непосредственно, позвольте мне показать эволюцию:

вы можете использовать методы экземпляра Array:

// general form of closure
images.sortInPlace({ (image1: imageFile, image2: imageFile) -> Bool in return image1.fileID > image2.fileID })

// types of closure's parameters and return value can be inferred by Swift, so they are omitted along with the return arrow (->)
images.sortInPlace({ image1, image2 in return image1.fileID > image2.fileID })

// Single-expression closures can implicitly return the result of their single expression by omitting the "return" keyword
images.sortInPlace({ image1, image2 in image1.fileID > image2.fileID })

// closure's argument list along with "in" keyword can be omitted, , , , and so on are used to refer the closure's first, second, third arguments and so on
images.sortInPlace({ .fileID > .fileID })

// the simplification of the closure is the same
images = images.sort({ (image1: imageFile, image2: imageFile) -> Bool in return image1.fileID > image2.fileID })
images = images.sort({ image1, image2 in return image1.fileID > image2.fileID })
images = images.sort({ image1, image2 in image1.fileID > image2.fileID })
images = images.sort({ .fileID > .fileID })

подробное объяснение принципа работы сортировки см. В разделе Функция Сортировки.


Swift 3

people = people.sorted(by: { .email > .email })

В Swift 3.0

images.sort(by: { (first: imageFile, second: imageFile) -> Bool in
    first. fileID < second. fileID
})

два варианта

1) Заказ оригинального массива с sortInPlace

self.assignments.sortInPlace({ .order < .order })
self.printAssignments(assignments)

2) используя альтернативный массив упорядоченный массив

var assignmentsO = [Assignment] ()
assignmentsO = self.assignments.sort({ .order < .order })
self.printAssignments(assignmentsO)

вы также можете сделать что-то вроде

images = sorted(images) {.fileID > .fileID}

таким образом, Ваш массив изображений будет сохранен как сортированный


С Swift 4, Array есть два метода, называемого sorted() и sorted(by:). Первый метод,sorted(), есть следующее объявление:

возвращает элементы коллекции, сортируют.

func sorted() -> [Element]

второй способ sorted(by:), есть следующее объявление:

возвращает элементы коллекции, отсортированные с использованием данного предиката в качестве сравнения между элементы.

func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]

1. Сортировка по возрастанию для сопоставимых объектов

если тип элемента внутри коллекции соответствует Comparable протокол, вы сможете использовать sorted() для сортировки элементов в порядке возрастания. Следующий код игровой площадки показывает, как использовать sorted():

class ImageFile: CustomStringConvertible, Comparable {

    let fileName: String
    let fileID: Int
    var description: String { return "ImageFile with ID: \(fileID)" }

    init(fileName: String, fileID: Int) {
        self.fileName = fileName
        self.fileID = fileID
    }

    static func ==(lhs: ImageFile, rhs: ImageFile) -> Bool {
        return lhs.fileID == rhs.fileID
    }

    static func <(lhs: ImageFile, rhs: ImageFile) -> Bool {
        return lhs.fileID < rhs.fileID
    }

}

let images = [
    ImageFile(fileName: "Car", fileID: 300),
    ImageFile(fileName: "Boat", fileID: 100),
    ImageFile(fileName: "Plane", fileID: 200)
]

let sortedImages = images.sorted()
print(sortedImages)

/*
 prints: [ImageFile with ID: 100, ImageFile with ID: 200, ImageFile with ID: 300]
 */

2. Сортировка по убыванию для сопоставимых объектов

если тип элемента внутри коллекция соответствует Comparable протокол, вам придется использовать sorted(by:) для сортировки элементов в порядке убывания.

class ImageFile: CustomStringConvertible, Comparable {

    let fileName: String
    let fileID: Int
    var description: String { return "ImageFile with ID: \(fileID)" }

    init(fileName: String, fileID: Int) {
        self.fileName = fileName
        self.fileID = fileID
    }

    static func ==(lhs: ImageFile, rhs: ImageFile) -> Bool {
        return lhs.fileID == rhs.fileID
    }

    static func <(lhs: ImageFile, rhs: ImageFile) -> Bool {
        return lhs.fileID < rhs.fileID
    }

}

let images = [
    ImageFile(fileName: "Car", fileID: 300),
    ImageFile(fileName: "Boat", fileID: 100),
    ImageFile(fileName: "Plane", fileID: 200)
]

let sortedImages = images.sorted(by: { (img0: ImageFile, img1: ImageFile) -> Bool in
    return img0 > img1
})
//let sortedImages = images.sorted(by: >) // also works
//let sortedImages = images.sorted {  >  } // also works
print(sortedImages)

/*
 prints: [ImageFile with ID: 300, ImageFile with ID: 200, ImageFile with ID: 100]
 */

3. Сортировка по возрастанию или убыванию для несопоставимых объектов

если тип элемента внутри вашей коллекции не соответствует Comparable протокол, вам придется использовать sorted(by:) для сортировки элементов по возрастанию или убыванию.

class ImageFile: CustomStringConvertible {

    let fileName: String
    let fileID: Int
    var description: String { return "ImageFile with ID: \(fileID)" }

    init(fileName: String, fileID: Int) {
        self.fileName = fileName
        self.fileID = fileID
    }

}

let images = [
    ImageFile(fileName: "Car", fileID: 300),
    ImageFile(fileName: "Boat", fileID: 100),
    ImageFile(fileName: "Plane", fileID: 200)
]

let sortedImages = images.sorted(by: { (img0: ImageFile, img1: ImageFile) -> Bool in
    return img0.fileID < img1.fileID
})
//let sortedImages = images.sorted { .fileID < .fileID } // also works
print(sortedImages)

/*
 prints: [ImageFile with ID: 300, ImageFile with ID: 200, ImageFile with ID: 100]
 */

обратите внимание, что Swift также предоставляет два метода с именем sort() и sort(by:) как аналоги sorted() и sorted(by:) если вам нужно сортировать свою коллекцию на месте.


Swift с 2 по 4

исходный ответ попыталась отсортировать массив пользовательских объектов с помощью некоторого свойства. Ниже я покажу вам несколько удобных способов сделать то же самое поведение с структурами данных swift!

мелочи в сторону, я немного изменил файл ImageFile. Имея это в виду, я создаю массив с три файлы изображений. Обратите внимание, что метаданные являются необязательным значением, передавая в качестве параметра nil ожидаемый.

 struct ImageFile {
      var name: String
      var metadata: String?
      var size: Int
    }

    var images: [ImageFile] = [ImageFile(name: "HelloWorld", metadata: nil, size: 256), ImageFile(name: "Traveling Salesmen", metadata: "uh this is huge", size: 1024), ImageFile(name: "Slack", metadata: "what's in this stuff?", size: 2048) ]

ImageFile имеет свойство с именем size. В следующих примерах я покажу вам, как использовать операции сортировки с такими свойствами, как размер.

наименьший к самому большому размеру (

    let sizeSmallestSorted = images.sorted { (initial, next) -> Bool in
      return initial.size < next.size
    }

от самого большого до самого маленького (>)

    let sizeBiggestSorted = images.sorted { (initial, next) -> Bool in
      return initial.size > next.size
    }

Далее мы будем сортировать, используя имя свойства строки. Таким же образом используйте sort для сравнения строк. Но обратите внимание, что внутренний блок возвращает результат сравнения. Этот результат определит сортировку.

A-Z (.orderedAscending)

    let nameAscendingSorted = images.sorted { (initial, next) -> Bool in
      return initial.name.compare(next.name) == .orderedAscending
    }

Z-A (.orderedDescending)

    let nameDescendingSorted = images.sorted { (initial, next) -> Bool in
      return initial.name.compare(next.name) == .orderedDescending
    }

далее мой любимый способ сортировки, во многих случаях один будет иметь дополнительные свойства. Теперь не волнуйтесь, мы будем сортировать так же, как и выше, за исключением того, что мы должны справиться с нулем! В производстве;

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

    let metadataFirst = images.sorted { (initial, next) -> Bool in
      guard initial.metadata != nil else { return true }
      guard next.metadata != nil else { return true }
      return initial.metadata!.compare(next.metadata!) == .orderedAscending
    }

возможно иметь вторичный вид для optionals. Например; можно показать изображения с метаданными и упорядоченные по размеру.


Swift 4.0 и 4.1. Во-первых, я создал изменяемый массив типа imageFile (), как показано ниже

var arr = [imageFile]()

создайте изменяемое изображение объекта типа imageFile () и назначьте значение свойствам, как показано ниже

   var image = imageFile()
   image.fileId = 14
   image.fileName = "A"

теперь добавьте этот объект в массив arr

    arr.append(image)

теперь назначьте различные свойства тому же изменяемому объекту i.e image

   image = imageFile()
   image.fileId = 13
   image.fileName = "B"

теперь снова добавьте объект изображения в массив arr

    arr.append(image)

теперь мы подадим заявку возрастающем порядке on fileId свойство в объектах arr массива. Использовать по возрастанию

 arr = arr.sorted(by: {.fileId < .fileId}) // arr has all objects in Ascending order
 print("sorted array is",arr[0].fileId)// sorted array is 13
 print("sorted array is",arr[1].fileId)//sorted array is 14

теперь мы будем применять нисходящем порядке on on fileId свойство в объектах arr массива. Использовать > символ по убыванию

 arr = arr.sorted(by: {.fileId > .fileId}) // arr has all objects in Descending order
 print("Unsorted array is",arr[0].fileId)// Unsorted array is 14
 print("Unsorted array is",arr[1].fileId)// Unsorted array is 13

В Swift 4.1. Для отсортированного заказа используйте

let sortedArr = arr.sorted { (id1, id2) -> Bool in
  return id1.fileId < id2.fileId // Use > for Descending order
}

Если вы собираетесь сортировать этот массив более чем в одном месте, может иметь смысл сделать ваш тип массива сопоставимым.

class MyImageType: Comparable, Printable {
    var fileID: Int

    // For Printable
    var description: String {
        get {
            return "ID: \(fileID)"
        }
    }

    init(fileID: Int) {
        self.fileID = fileID
    }
}

// For Comparable
func <(left: MyImageType, right: MyImageType) -> Bool {
    return left.fileID < right.fileID
}

// For Comparable
func ==(left: MyImageType, right: MyImageType) -> Bool {
    return left.fileID == right.fileID
}

let one = MyImageType(fileID: 1)
let two = MyImageType(fileID: 2)
let twoA = MyImageType(fileID: 2)
let three = MyImageType(fileID: 3)

let a1 = [one, three, two]

// return a sorted array
println(sorted(a1)) // "[ID: 1, ID: 2, ID: 3]"

var a2 = [two, one, twoA, three]

// sort the array 'in place'
sort(&a2)
println(a2) // "[ID: 1, ID: 2, ID: 2, ID: 3]"

Если вы используете не пользовательские объекты, а типы значений, которые реализуют сопоставимый протокол (Int, String и т. д..) вы можете просто сделать это:

myArray.sort(>) //sort descending order

пример:

struct MyStruct: Comparable {
    var name = "Untitled"
}

func <(lhs: MyStruct, rhs: MyStruct) -> Bool {
    return lhs.name < rhs.name
}
// Implementation of == required by Equatable
func ==(lhs: MyStruct, rhs: MyStruct) -> Bool {
    return lhs.name == rhs.name
}

let value1 = MyStruct()
var value2 = MyStruct()

value2.name = "A New Name"

var anArray:[MyStruct] = []
anArray.append(value1)
anArray.append(value2)

anArray.sort(>) // This will sort the array in descending order

если вы хотите отсортировать исходный массив пользовательских объектов. Вот еще один способ сделать это в Swift 2.1

var myCustomerArray = [Customer]()
myCustomerArray.sortInPlace {(customer1:Customer, customer2:Customer) -> Bool in
    customer1.id < customer2.id
}

здесь id - целое число. Вы можете использовать то же самое < оператора String свойства, а также.

вы можете узнать больше о его использовании на примере здесь: Swift2: Ближайшие Клиенты


var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]

students.sort(by: >)

print(students)

принты : "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"


Я делаю это так, и это работает:

var images = [imageFile]() images.sorted(by: {.fileID.compare(.fileID) == .orderedAscending })