Veloce come ordinare la matrice di oggetti personalizzati in base al valore della proprietà


521

diciamo che abbiamo una classe personalizzata denominata imageFile e questa classe contiene due proprietà.

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

molti di loro memorizzati in 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)

domanda è: come posso ordinare l'array di immagini in base a 'fileID' ASC o DESC?


Risposte:


941

Prima di tutto, dichiara il tuo array come un array tipizzato in modo da poter chiamare i metodi quando esegui l'iterazione:

var images : [imageFile] = []

Quindi puoi semplicemente fare:

Swift 2

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

Swift 3+

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

L'esempio sopra mostra l' ordinamento desc


1
Mi mancava la parte di dichiarazione dell'array, ha fatto il trucco Array <imageFile>.
Mohacs,

1
@AlexWayne Ho una NSManagedObjectsottoclasse chiamata CheckInAndOut . E in un file separato, ho dichiarato un array tipizzato per oggetti di questo tipo e quando provo a ordinarlo , ottengo un errore Impossibile trovare il membro . Qualche idea sul perché questo sia?
Isuru,

3
Ho trovato il mio problema Apparentemente l'array non era un array tipizzato. Comunque ho un nuovo problema. Come posso ordinare un array per più proprietà? Supponiamo che io abbia 2 proprietà come firstNamee lastNamein una matrice di Personoggetti. Prima voglio ordinarlo firstNamee poi lastName. Come posso farlo?
Isuru,

12
ora devi fare images.sortInPlace({ $0.fileID > $1.fileID })?
Taylor M,

13
nel caso in cui qualcuno si stia chiedendo lo stesso: la risposta darà l'ordine di descrizione
Danny Wang

223

[ Aggiornato per Swift 3 con ordinamento (per :) ] Questo, sfruttando una chiusura finale:

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

dove si utilizza <o in >base a ASC o DESC, rispettivamente. Se si desidera modificare l' imagesarray , utilizzare quanto segue:

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

Se lo farai ripetutamente e preferisci definire una funzione, un modo è:

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

e quindi utilizzare come:

images.sort(by: sorterForFileIDASC)

come posso fare causa con lo spago? ho bisogno di ordinare la stringa per la sua lunghezza
Muneef M

@MuneefM ha appena restituito string1.length <string2.length
Surjeet Rajput

sortnon viene più compilata con questa sintassi in Xcode 8. Xcode 8 dice che $0.fileID < $1.fileIDproduce un valore Bool non ComparisonResult.
Crashalot,

3
Il codice di questa risposta funziona bene in Xcode8; se hai un errore, pubblica una nuova domanda.
GoZoner,

Posso usarlo anche per ordinare in base a confronti, ad esempio avere l'ordinamento di array in base ai giorni della settimana? se é cosi, come?
Kristofer,

53

Quasi tutti danno come direttamente, fammi mostrare l'evoluzione:

puoi usare i metodi di istanza di 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 })

Per una spiegazione dettagliata del principio di funzionamento dell'ordinamento, vedere La funzione ordinata .


Posso usarlo anche per ordinare in base a confronti, ad esempio avere l'ordinamento di array in base ai giorni della settimana? se é cosi, come?
Kristofer,

Grazie per aver pubblicato una risposta che mostra come funziona una chiusura invece di supporre che i lettori comprendano la sintassi criptica della chiusura "semplificata"!
user1118321

50

Swift 3

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

ho provato questo con un confronto delle date, non sono riuscito a farlo funzionare. Qualche idea?
Ebru Güngör,

Non NSDate o String, oggetto data rapido rapido 3.
Ebru Güngör,

Quale proprietà di Date stai confrontando? La proprietà deve poter essere confrontata con la funzione utilizzata (maggiore rispetto al mio esempio)
quemeful

9
Questa è l'unica risposta utile per il 2017 in poi.
Fattie,

@Fattie Che vuoi dire? La sintassi corretta èpeople.sort { $0.email > $1.email }
Leo Dabus,

43

Con Swift 5, Arrayha due metodi chiamati sorted()e sorted(by:). Il primo metodo, sorted()ha la seguente dichiarazione:

Restituisce gli elementi della raccolta, ordinati.

func sorted() -> [Element]

Il secondo metodo, sorted(by:)ha la seguente dichiarazione:

Restituisce gli elementi della raccolta, ordinati usando il predicato indicato come confronto tra elementi.

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

# 1. Ordina in ordine crescente per oggetti comparabili

Se il tipo di elemento all'interno della tua raccolta è conforme al Comparableprotocollo, sarai in grado di utilizzare sorted()per ordinare i tuoi elementi in ordine crescente. Il seguente codice Playground mostra come usare 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. Ordina in ordine decrescente per oggetti comparabili

Se il tipo di elemento all'interno della tua raccolta è conforme al Comparableprotocollo, dovrai usarlo sorted(by:)per ordinare i tuoi elementi in ordine decrescente.

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. Ordina con ordine crescente o decrescente per oggetti non confrontabili

Se il tipo di elemento all'interno della tua raccolta NON È conforme al Comparableprotocollo, dovrai usarlo sorted(by:)per ordinare i tuoi elementi in ordine crescente o decrescente.

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

Si noti che Swift fornisce anche due metodi chiamati sort()e sort(by:)come controparti di sorted()e sorted(by:)se è necessario ordinare la propria raccolta sul posto.


25

In Swift 3.0

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

20

Puoi anche fare qualcosa del genere

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

così il tuo array di immagini verrà archiviato come ordinato


19

Passa da 2 a 4

La risposta originale ha cercato di ordinare una matrice di oggetti personalizzati usando alcune proprietà. Di seguito ti mostrerò alcuni modi pratici per fare lo stesso comportamento con veloci strutture di dati!

Piccole cose fuori mano, ho cambiato ImageFile molto leggermente. Con questo in mente, creo un array con tre file di immagini. Si noti che i metadati sono un valore facoltativo, passando a zero come parametro previsto.

 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 ha una proprietà denominata size. Per i seguenti esempi ti mostrerò come utilizzare le operazioni di ordinamento con proprietà come dimensione.

dimensioni dalla più piccola alla più grande (<)

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

dal più grande al più piccolo (>)

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

Successivamente ordineremo usando il nome della proprietà String. Allo stesso modo, utilizzare l'ordinamento per confrontare le stringhe. Si noti che il blocco interno restituisce un risultato di confronto. Questo risultato definirà l'ordinamento.

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
    }

Il prossimo è il mio modo preferito di ordinare, in molti casi uno avrà proprietà opzionali. Ora non ti preoccupare, andremo a sistemare come sopra, tranne che dobbiamo gestire zero! In produzione;

Ho usato questo codice per forzare tutte le istanze nel mio array con valori di proprietà nul a durare. Quindi ordina i metadati utilizzando i valori non imballati assunti.

    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
    }

È possibile avere un ordinamento secondario per gli optional. Per esempio; si potrebbero mostrare immagini con metadati e ordinate per dimensione.


1
In generale, le risposte sono molto più utili se includono una spiegazione di ciò che il codice è destinato a fare e perché risolve il problema senza introdurre altri.
Tom Aranda,

Molto meglio.
Tom Aranda,

18

Due alternative

1) Ordinare l'array originale con sortInPlace

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

2) Utilizzo di un array alternativo per memorizzare l'array ordinato

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

3
ri 2) Qual è il punto nel costruire un array vuoto e scartarlo nella riga successiva? Userei var assignmentsO : [Assignment]o combinerei in una riga usandolet assignmentsO = self.assignments.sort({ $0.order < $1.order })
Hermann Klecker il

2
Ciao Hermann! Esiste una linea molto sottile tra la scrittura di codice leggibile ed efficiente. In questo caso, l'unico punto è renderlo più leggibile per la comunità;) divertiti!
Bernauer,

18

Swift 4.0, 4.1 e 4.2 Innanzitutto, ho creato un array mutabile di tipo imageFile () come mostrato di seguito

var arr = [imageFile]()

Crea un'immagine oggetto mutabile di tipo imageFile () e assegna valore alle proprietà come mostrato di seguito

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

Ora, aggiungi questo oggetto all'array arr

    arr.append(image)

Ora, assegna le diverse proprietà allo stesso oggetto mutabile, ad esempio immagine

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

Ora, aggiungi di nuovo l'oggetto immagine all'array arr

    arr.append(image)

Ora applicheremo l' ordine crescente sulla proprietà fileId negli oggetti arr array. Utilizzare il simbolo < per Ordine crescente

 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

Ora applicheremo l' ordine decrescente sulla proprietà fileId negli oggetti arr array. Usa > simbolo per Ordine decrescente

 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

In Swift 4.1. & 4.2 Per l'uso in ordini ordinati

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

8

Se stai per ordinare questo array in più di un posto, può essere logico rendere comparabile il tuo tipo di array.

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]"

6

Se non stai utilizzando oggetti personalizzati, ma invece tipi di valore che implementano il protocollo comparabile (Int, String ecc.) Puoi semplicemente fare questo:

myArray.sort(>) //sort descending order

Un esempio:

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

nel rapido 3 èmyArray.sorted(by: >)
berillio il

6

Si restituisce un array ordinato dalla proprietà fileID nel modo seguente:

Swift 2

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

Swift 3 OPPURE 4

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

Swift 5.0

let sortedArray = images.sorted {
    $0.fileID < $1.fileID
}

Funziona come un fascino .. votato! (Pratik Prajapati, Ahmedabad)
NSPratik,

4

Lo faccio in questo modo e funziona:

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


2

Se si desidera ordinare l'array originale di oggetti personalizzati. Ecco un altro modo per farlo in Swift 2.1

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

Dov'è idun numero intero. Puoi usare lo stesso <operatore anche per le Stringproprietà.

Puoi saperne di più sul suo utilizzo guardando un esempio qui: Swift2: clienti nelle vicinanze


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

students.sort(by: >)

print(students)

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


1

Swift 3 & 4 & 5

Ho avuto qualche problema relativo al minuscolo e al maiuscolo

quindi ho fatto questo codice

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

e successivamente usa sortImages


0

Ordina utilizzando KeyPath

puoi ordinare in KeyPathquesto modo:

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

Implementando questa piccola utile estensione.

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

Spero che Swift lo aggiunga nel prossimo futuro nel cuore della lingua.


A questo è già stato risposto qui stackoverflow.com/a/46601105/2303865 insieme al metodo di mutazione.
Leo Dabus,

la versione 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.