Swift cara mengurutkan array objek khusus berdasarkan nilai properti

521

katakanlah kita memiliki kelas khusus bernama imageFile dan kelas ini berisi dua properti.

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

banyak dari mereka disimpan di 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)

pertanyaannya adalah: bagaimana saya bisa mengurutkan array gambar dengan 'fileID' ASC atau DESC?

mohac
sumber
urutkan berdasarkan KeyPath stackoverflow.com/a/46601105/2303865
Leo Dabus

Jawaban:

941

Pertama, nyatakan Array Anda sebagai array yang diketik sehingga Anda dapat memanggil metode saat Anda mengulangi:

var images : [imageFile] = []

Maka Anda cukup melakukan:

Cepat 2

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

Swift 3+

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

Contoh di atas memberikan urutan penguraian

Alex Wayne
sumber
1
Saya kehilangan bagian deklarasi array, itu memang trik Array <imageFile>.
mohacs
1
@AlexWayne Saya memiliki NSManagedObjectsubkelas yang disebut CheckInAndOut . Dan dalam file terpisah, saya telah mendeklarasikan array yang diketik untuk objek jenis ini dan ketika saya mencoba untuk mengurutkannya , saya mendapatkan Tidak dapat menemukan kesalahan anggota . ada yang tahu ini kenapa?
Isuru
3
Saya menemukan masalah saya. Rupanya array itu bukan array yang diketik. Pokoknya saya punya masalah baru. Bagaimana saya bisa mengurutkan array berdasarkan beberapa properti? Katakanlah saya memiliki 2 properti suka firstNamedan lastNamedalam array Personobjek. Pertama saya ingin mengatasinya firstNamedulu lastName. Bagaimana saya bisa melakukan ini?
Isuru
12
yang perlu Anda lakukan sekarang images.sortInPlace({ $0.fileID > $1.fileID })?
Taylor M
13
kalau-kalau ada yang bertanya-tanya sama: jawabannya akan memberi perintah desc
Danny Wang
223

[ Diperbarui untuk Swift 3 dengan sortir (berdasarkan :) ] Ini, mengeksploitasi penutupan tambahan:

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

di mana Anda menggunakan <atau >bergantung pada ASC atau DESC, masing-masing. Jika Anda ingin memodifikasi imagesarray , gunakan yang berikut ini:

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

Jika Anda akan melakukan ini berulang kali dan lebih memilih untuk mendefinisikan suatu fungsi, salah satu caranya adalah:

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

dan kemudian gunakan sebagai:

images.sort(by: sorterForFileIDASC)
GoZoner
sumber
bagaimana saya bisa menuntut ini dengan string? saya perlu mengurutkan string berdasarkan panjangnya
Muneef M
@MuneefM baru saja mengembalikan string1.length <string2.length
Rajput
sorttidak lagi mengkompilasi dengan sintaks ini di Xcode 8. Xcode 8 mengatakan $0.fileID < $1.fileIDmenghasilkan Bool bukan ComparisonResult.
Crashalot
3
Kode jawaban ini berfungsi dengan baik di Xcode8; jika Anda memiliki kesalahan, kirim pertanyaan baru.
GoZoner
Bisakah saya juga menggunakan ini untuk mengurutkan berdasarkan perbandingan, misalnya memiliki array yang diurutkan berdasarkan hari dalam seminggu? jika demikian bagaimana?
Kristofer
53

Hampir semua orang memberikan caranya secara langsung, izinkan saya menunjukkan evolusi:

Anda dapat menggunakan metode instance 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 })

Untuk penjelasan terperinci tentang prinsip kerja sortir, lihat The Sorted Function .

fujianjin6471
sumber
Bisakah saya juga menggunakan ini untuk mengurutkan berdasarkan perbandingan, misalnya memiliki array yang diurutkan berdasarkan hari dalam seminggu? jika demikian bagaimana?
Kristofer
Terima kasih telah mengirim jawaban yang menunjukkan cara kerja penutupan alih-alih menganggap pembaca memahami sintaksis samar dari penutupan "sederhana"!
user1118321
50

Cepat 3

people = people.sorted(by: { $0.email > $1.email })
unik
sumber
Saya sudah mencoba ini dengan perbandingan tanggal, tidak bisa membuatnya bekerja. Ada ide?
Ebru Güngör
Bukan NSDate atau String, objek 3 Date swift saat ini.
Ebru Güngör
Properti mana dari Date yang Anda bandingkan? Properti harus dapat dibandingkan dengan fungsi yang digunakan (lebih besar dari pada contoh saya)
quemeful
9
Ini adalah satu-satunya jawaban yang berguna untuk 2017 dan seterusnya.
Fattie
@Fattie Apa maksudmu? Sintaks yang benar adalahpeople.sort { $0.email > $1.email }
Leo Dabus
43

Dengan Swift 5, Arraymemiliki dua metode yang disebut sorted()dan sorted(by:). Metode pertama sorted(),, memiliki deklarasi berikut:

Mengembalikan elemen koleksi, diurutkan.

func sorted() -> [Element]

Metode kedua sorted(by:),, memiliki deklarasi berikut:

Mengembalikan elemen koleksi, diurutkan menggunakan predikat yang diberikan sebagai perbandingan antar elemen.

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

# 1. Urutkan dengan urutan menaik untuk objek yang sebanding

Jika tipe elemen di dalam koleksi Anda sesuai dengan Comparableprotokol, Anda akan dapat menggunakannya sorted()untuk mengurutkan elemen Anda dengan urutan menaik. Kode Playground berikut menunjukkan cara menggunakan 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. Urutkan dengan urutan menurun untuk objek yang sebanding

Jika tipe elemen di dalam koleksi Anda sesuai dengan Comparableprotokol, Anda harus menggunakannya sorted(by:)untuk mengurutkan elemen Anda dengan urutan menurun.

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. Urutkan dengan urutan naik atau turun untuk objek yang tidak sebanding

Jika jenis elemen di dalam koleksi Anda TIDAK sesuai dengan Comparableprotokol, Anda harus menggunakan sorted(by:)untuk mengurutkan elemen Anda dengan urutan naik atau turun.

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

Perhatikan bahwa Swift juga menyediakan dua metode yang disebut sort()dan sort(by:)sebagai mitra sorted()dan sorted(by:)jika Anda perlu mengurutkan koleksi di tempat.

Imanou Petit
sumber
25

Di Swift 3.0

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

Anda juga dapat melakukan sesuatu seperti

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

jadi array gambar Anda akan disimpan sebagai diurutkan

Nicolas Grenié
sumber
19

Swift 2 hingga 4

Jawaban asli berusaha mengurutkan array objek kustom menggunakan beberapa properti. Di bawah ini saya akan menunjukkan kepada Anda beberapa cara praktis untuk melakukan perilaku yang sama dengan struktur data cepat!

Hal-hal kecil keluar dari jalan, saya mengubah ImageFile sedikit. Dengan mengingat hal itu, saya membuat array dengan tiga file gambar. Perhatikan bahwa metadata adalah nilai opsional, melewati nil sebagai parameter yang diharapkan.

 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 memiliki ukuran properti bernama. Untuk contoh berikut saya akan menunjukkan kepada Anda bagaimana menggunakan operasi sortir w / properti seperti ukuran.

ukuran terkecil hingga terbesar (<)

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

terbesar ke terkecil (>)

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

Selanjutnya kita akan mengurutkan menggunakan nama properti String. Dengan cara yang sama, gunakan sortir untuk membandingkan string. Tetapi perhatikan blok dalam mengembalikan hasil perbandingan. Hasil ini akan menentukan jenis.

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
    }

Berikutnya adalah cara favorit saya untuk mengurutkan, dalam banyak kasus seseorang akan memiliki properti opsional. Sekarang jangan khawatir, kita akan mengurutkan dengan cara yang sama seperti di atas kecuali kita harus menangani nihil! Dalam produksi;

Saya menggunakan kode ini untuk memaksa semua instance dalam array saya dengan nilai properti nil menjadi yang terakhir. Kemudian pesan metadata menggunakan nilai yang diasumsikan terbuka.

    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
    }

Dimungkinkan untuk memiliki jenis sekunder untuk opsional. Sebagai contoh; orang dapat menampilkan gambar dengan metadata dan dipesan berdasarkan ukuran.

jnblanchard
sumber
1
Secara umum, jawaban akan jauh lebih membantu jika mereka menyertakan penjelasan tentang apa yang dimaksudkan untuk dilakukan oleh kode, dan mengapa hal itu menyelesaikan masalah tanpa memperkenalkan orang lain.
Tom Aranda
Jauh lebih baik.
Tom Aranda
18

Dua alternatif

1) Memesan array asli dengan sortInPlace

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

2) Menggunakan array alternatif untuk menyimpan array yang dipesan

var assignmentsO = [Assignment] ()
assignmentsO = self.assignments.sort({ $0.order < $1.order })
self.printAssignments(assignmentsO)
Bernauer
sumber
3
re 2) Apa gunanya membangun array kosong dan membuangnya di baris berikutnya? Saya sugest menggunakan var assignmentsO : [Assignment]atau menggabungkannya menjadi satu baris dengan menggunakanlet assignmentsO = self.assignments.sort({ $0.order < $1.order })
Hermann Klecker
2
Hai Hermann! Ada garis yang sangat tipis antara penulisan kode yang dapat dibaca dan efisien. Dalam hal ini, satu-satunya poin adalah membuatnya lebih mudah dibaca oleh komunitas;) selamat menikmati!
Bernauer
18

Swift 4.0, 4.1 & 4.2 Pertama, saya membuat array bertipe typeFileFile () seperti yang ditunjukkan di bawah ini

var arr = [imageFile]()

Buat gambar objek yang dapat diubah dari tipe imageFile () dan berikan nilai pada properti seperti yang ditunjukkan di bawah ini

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

Sekarang, tambahkan objek ini ke array array

    arr.append(image)

Sekarang, tetapkan properti yang berbeda untuk objek yang bisa berubah yaitu gambar

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

Sekarang, lagi-lagi tambahkan objek gambar ke array array

    arr.append(image)

Sekarang, kita akan menerapkan urutan naik pada properti fileId di objek array array. Gunakan <simbol untuk urutan naik

 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

Sekarang, kita akan menerapkan urutan Descending pada properti fileId di objek array array. Gunakan > simbol untuk urutan Descending

 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

Dalam Swift 4.1. & 4.2 Untuk penggunaan pesanan yang diurutkan

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

Jika Anda akan mengurutkan array ini di lebih dari satu tempat, mungkin masuk akal untuk membuat tipe array Anda Sebanding.

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
sumber
6

Jika Anda tidak menggunakan objek kustom, tetapi sebaliknya tipe nilai yang mengimplementasikan protokol Sebanding (Int, String dll.) Anda bisa melakukan ini:

myArray.sort(>) //sort descending order

Sebuah contoh:

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
dorian
sumber
dalam 3 cepat itumyArray.sorted(by: >)
berilium
6

Anda mengembalikan array yang diurutkan dari properti fileID dengan cara berikut:

Cepat 2

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

Cepat 3 ATAU 4

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

Swift 5.0

let sortedArray = images.sorted {
    $0.fileID < $1.fileID
}
Vicky Prajapati
sumber
Berfungsi seperti pesona .. ditingkatkan! (Pratik Prajapati, Ahmedabad)
NSPratik
4

Saya melakukannya seperti ini dan berfungsi:

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

Illya Krit
sumber
2

Jika Anda ingin mengurutkan array asli objek kustom. Berikut cara lain untuk melakukannya di Swift 2.1

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

Dimana idInteger. Anda dapat menggunakan <operator yang sama untuk Stringproperti juga.

Anda dapat mempelajari lebih lanjut tentang penggunaannya dengan melihat contoh di sini: Swift2: Pelanggan Terdekat

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

students.sort(by: >)

print(students)

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

Siddharth Chauhan
sumber
1

Swift 3 & 4 & 5

Saya memiliki beberapa masalah terkait dengan huruf kecil dan huruf besar

jadi saya melakukan kode ini

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

dan kemudian gunakan SortImages setelah itu

Abdelrahman Mohamed
sumber
0

Sortir menggunakan KeyPath

Anda dapat mengurutkan berdasarkan KeyPathini:

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

Dengan menerapkan ekstensi kecil yang bermanfaat ini.

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 menambahkan ini dalam waktu dekat di inti bahasa.

Mojtaba Hosseini
sumber
Ini telah dijawab di sini stackoverflow.com/a/46601105/2303865 bersama dengan metode mutasi juga.
Leo Dabus
versi bermutasipublic 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