Rápido cómo ordenar la matriz de objetos personalizados por valor de propiedad

521

Digamos que tenemos una clase personalizada llamada imageFile y esta clase contiene dos propiedades.

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

muchos de ellos almacenados en Array

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)

la pregunta es: ¿cómo puedo ordenar la matriz de imágenes por 'fileID' ASC o DESC?

mohacs
fuente
ordenar por KeyPath stackoverflow.com/a/46601105/2303865
Leo Dabus

Respuestas:

941

Primero, declare su matriz como una matriz escrita para que pueda llamar a los métodos cuando itera:

var images : [imageFile] = []

Entonces simplemente puedes hacer:

Swift 2

images.sorted({ $0.fileID > $1.fileID })

Swift 3+

images.sorted(by: { $0.fileID > $1.fileID })

El ejemplo anterior muestra el orden de clasificación desc

Alex Wayne
fuente
1
Me faltaba parte de la declaración de matriz, hizo el truco Array <imageFile>.
mohacs
1
@AlexWayne Tengo una NSManagedObjectsubclase llamada CheckInAndOut . Y en un archivo separado, he declarado una matriz escrita para objetos de este tipo y cuando trato de ordenarlo , aparece un error No se pudo encontrar el miembro . ¿Alguna idea de por qué es esto?
Isuru
3
Encontré mi problema. Aparentemente, la matriz no era una matriz escrita. De todos modos tengo un nuevo problema. ¿Cómo puedo ordenar una matriz por varias propiedades? Digamos que tengo 2 propiedades como firstNamey lastNameen una matriz de Personobjetos. Primero quiero ordenarlo firstNamey luego lastName. ¿Cómo puedo hacer esto?
Isuru
12
¿Ahora necesitas hacer images.sortInPlace({ $0.fileID > $1.fileID })?
Taylor M
13
en caso de que alguien se está preguntando lo mismo: la respuesta dará fin desc
Danny Wang
223

[ Actualizado para Swift 3 con sort (by :) ] Esto, explotando un cierre final:

images.sorted { $0.fileID < $1.fileID }

donde usa <o >depende de ASC o DESC, respectivamente. Si desea modificar la imagesmatriz , use lo siguiente:

images.sort { $0.fileID < $1.fileID }

Si va a hacer esto repetidamente y prefiere definir una función, una forma es:

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

y luego usar como:

images.sort(by: sorterForFileIDASC)
GoZoner
fuente
¿Cómo puedo demandar esto con una cuerda? necesito ordenar la cadena por su longitud
Muneef M
@MuneefM solo devuelve string1.length <string2.length
Surjeet Rajput
sortya no se compila con esta sintaxis en Xcode 8. Xcode 8 dice que $0.fileID < $1.fileIDproduce un resultado Bool no ComparisonResult.
Crashalot
3
El código de esta respuesta funciona bien en Xcode8; Si tiene un error, publique una nueva pregunta.
GoZoner
¿Puedo usar esto también para ordenar por comparaciones, por ejemplo, ordenar la matriz por días de la semana? ¿si es así, cómo?
Kristofer
53

Casi todos dan cómo directamente, déjenme mostrarles la evolución:

puede usar los métodos de instancia de 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, $0, $1, $2, and so on are used to refer the closure's first, second, third arguments and so on
images.sortInPlace({ $0.fileID > $1.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({ $0.fileID > $1.fileID })

Para obtener una explicación detallada sobre el principio de funcionamiento del ordenamiento, consulte La función ordenada .

Fujianjin6471
fuente
¿Puedo usar esto también para ordenar por comparaciones, por ejemplo, ordenar la matriz por días de la semana? ¿si es así, cómo?
Kristofer
¡Gracias por publicar una respuesta que muestra cómo funciona un cierre en lugar de asumir que los lectores entienden la sintaxis críptica del cierre "simplificado"!
user1118321
50

Swift 3

people = people.sorted(by: { $0.email > $1.email })
malicioso
fuente
He intentado esto con una comparación de fechas, no pude hacerlo funcionar. ¿Alguna idea?
Ebru Güngör
No NSDate o String, objeto actual de fecha 3 veloz.
Ebru Güngör
¿Qué propiedad de Date estás comparando? La propiedad debe poder compararse con la función utilizada (mayor que en mi ejemplo)
consulta el
99
Esta es la única respuesta útil para 2017 en adelante.
Fattie
@Fattie ¿Qué quieres decir? La sintaxis correcta espeople.sort { $0.email > $1.email }
Leo Dabus el
43

Con Swift 5, Arraytiene dos métodos llamados sorted()y sorted(by:). El primer método, sorted()tiene la siguiente declaración:

Devuelve los elementos de la colección, ordenados.

func sorted() -> [Element]

El segundo método, sorted(by:)tiene la siguiente declaración:

Devuelve los elementos de la colección, ordenados usando el predicado dado como la comparación entre elementos.

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

# 1 Ordenar con orden ascendente para objetos comparables

Si el tipo de elemento dentro de su colección se ajusta al Comparableprotocolo, podrá usarlo sorted()para ordenar sus elementos en orden ascendente. El siguiente código de Playground muestra cómo usar 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 Ordenar con orden descendente para objetos comparables

Si el tipo de elemento dentro de su colección se ajusta al Comparableprotocolo, deberá usarlo sorted(by:)para ordenar sus elementos con un orden descendente.

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 { $0 > $1 } // also works
print(sortedImages)

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

# 3 Ordenar con orden ascendente o descendente para objetos no comparables

Si el tipo de elemento dentro de su colección NO se ajusta al Comparableprotocolo, deberá usarlo sorted(by:)para ordenar sus elementos en orden ascendente o descendente.

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 { $0.fileID < $1.fileID } // also works
print(sortedImages)

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

Tenga en cuenta que Swift también proporciona dos métodos llamados sort()y sort(by:)como contrapartes de sorted()y sorted(by:)si necesita ordenar su colección en el lugar.

Imanou Petit
fuente
25

En Swift 3.0

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

También puedes hacer algo como

images = sorted(images) {$0.fileID > $1.fileID}

por lo que su matriz de imágenes se almacenará ordenada

Nicolas Grenié
fuente
19

Swift 2 a 4

La respuesta original buscaba ordenar una matriz de objetos personalizados usando alguna propiedad. A continuación, le mostraré algunas maneras prácticas de hacer este mismo comportamiento con estructuras de datos rápidas.

Pequeñas cosas fuera del camino, cambié ImageFile muy ligeramente. Con eso en mente, creo una matriz con tres archivos de imagen. Tenga en cuenta que los metadatos son un valor opcional, pasando nil como se espera un parámetro.

 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 tiene una propiedad llamada size. Para los siguientes ejemplos, le mostraré cómo usar operaciones de clasificación con propiedades como tamaño.

tamaño más pequeño a más grande (<)

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

mayor a menor (>)

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

A continuación, ordenaremos utilizando el nombre de la propiedad String. De la misma manera, use sort para comparar cadenas. Pero observe que el bloque interno devuelve un resultado de comparación. Este resultado definirá la ordenación.

AZ (.orderedAscending)

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

ZA (.orderedDescending)

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

La siguiente es mi forma favorita de ordenar, en muchos casos uno tendrá propiedades opcionales. Ahora no se preocupe, vamos a ordenar de la misma manera que antes, ¡excepto que tenemos que manejar nulo! En producción;

Usé este código para forzar que todas las instancias en mi matriz con valores de propiedad nulos sean las últimas. Luego ordene los metadatos utilizando los supuestos valores sin envolver.

    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
    }

Es posible tener una clasificación secundaria para opcionales. Por ejemplo; se podrían mostrar imágenes con metadatos y ordenadas por tamaño.

jnblanchard
fuente
1
En general, las respuestas son mucho más útiles si incluyen una explicación de lo que se pretende que haga el código y por qué eso resuelve el problema sin introducir otros.
Tom Aranda
Mucho, mucho mejor.
Tom Aranda
18

Dos alternativas

1) Ordenar la matriz original con sortInPlace

self.assignments.sortInPlace({ $0.order < $1.order })
self.printAssignments(assignments)

2) Usar una matriz alternativa para almacenar la matriz ordenada

var assignmentsO = [Assignment] ()
assignmentsO = self.assignments.sort({ $0.order < $1.order })
self.printAssignments(assignmentsO)
Bernauer
fuente
3
re 2) ¿Cuál es el punto de construir una matriz vacía y descartarla en la siguiente línea? Me sugest utilizar var assignmentsO : [Assignment]o combinar en una sola línea mediante el uso delet assignmentsO = self.assignments.sort({ $0.order < $1.order })
Hermann Klecker
2
Hola hermann Hay una línea muy delgada entre escribir código legible y eficiente. En este caso, el único punto es hacerlo más legible para la comunidad;) ¡disfruta!
Bernauer
18

Swift 4.0, 4.1 y 4.2 Primero, creé una matriz mutable de tipo imageFile () como se muestra a continuación

var arr = [imageFile]()

Cree una imagen de objeto mutable de tipo imageFile () y asigne valor a las propiedades como se muestra a continuación

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

Ahora, agregue este objeto a la matriz arr

    arr.append(image)

Ahora, asigne las diferentes propiedades al mismo objeto mutable, es decir, imagen

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

Ahora, agregue nuevamente el objeto de imagen al arreglo arr

    arr.append(image)

Ahora, aplicaremos el orden Ascendente en la propiedad fileId en los objetos arr de la matriz. Use el símbolo < para orden ascendente

 arr = arr.sorted(by: {$0.fileId < $1.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

Ahora, aplicaremos el orden Descendente en la propiedad fileId en los objetos de matriz arr. Use el símbolo> para orden descendente

 arr = arr.sorted(by: {$0.fileId > $1.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

En Swift 4.1. & 4.2 Para uso de orden ordenada

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

Si va a ordenar esta matriz en más de un lugar, puede tener sentido hacer que su tipo de matriz sea Comparable.

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]"
kwerle
fuente
6

Si no está utilizando objetos personalizados, sino tipos de valores que implementan un protocolo comparable (Int, String, etc.), simplemente puede hacer esto:

myArray.sort(>) //sort descending order

Un ejemplo:

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
dorio
fuente
en swift 3 esmyArray.sorted(by: >)
berilio
6

Devuelve una matriz ordenada de la propiedad fileID de la siguiente manera:

Swift 2

let sortedArray = images.sorted({ $0.fileID > $1.fileID })

Swift 3 o 4

let sortedArray = images.sorted(by: { $0.fileID > $1.fileID })

Swift 5.0

let sortedArray = images.sorted {
    $0.fileID < $1.fileID
}
Vicky Prajapati
fuente
Funciona como un encanto ... ¡votado! (Pratik Prajapati, Ahmedabad)
NSPratik
4

Lo hago así y funciona:

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

Illya Krit
fuente
2

Si desea ordenar la matriz original de objetos personalizados. Aquí hay otra forma de hacerlo en Swift 2.1

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

¿Dónde idestá un número entero? También puede usar el mismo <operador para las Stringpropiedades.

Puede obtener más información sobre su uso mirando un ejemplo aquí: Swift2: Clientes cercanos

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

students.sort(by: >)

print(students)

Impresiones: "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"

Siddharth Chauhan
fuente
1

Swift 3 y 4 y 5

Tuve algún problema relacionado con minúsculas y mayúsculas

entonces hice este código

let sortedImages = images.sorted(by: { $0.fileID.lowercased() < $1.fileID.lowercased() })

y luego usar imágenes ordenadas después de eso

Abdelrahman Mohamed
fuente
0

Ordenar usando KeyPath

puedes ordenar de KeyPathesta manera:

myArray.sorted(by: \.fileName, <) /* using `<` for ascending sorting */

Al implementar esta pequeña extensión útil.

extension Collection{
    func sorted<Value: Comparable>(
        by keyPath: KeyPath<Element, Value>,
        _ comparator: (_ lhs: Value, _ rhs: Value) -> Bool) -> [Element] {
        sorted { comparator($0[keyPath: keyPath], $1[keyPath: keyPath]) }
    }
}

Hope Swift agregará esto en un futuro cercano en el núcleo del lenguaje.

Mojtaba Hosseini
fuente
Esto ya se ha respondido aquí stackoverflow.com/a/46601105/2303865 junto con el método de mutación también.
Leo Dabus
la versión mutantepublic extension MutableCollection where Self: RandomAccessCollection { mutating func sort<T>(_ keyPath: KeyPath<Element, T>, by areInIncreasingOrder: (T, T) throws -> Bool) rethrows where T: Comparable { try sort { try areInIncreasingOrder($0[keyPath: keyPath], $1[keyPath: keyPath]) } }}
Leo Dabus