Swift cách sắp xếp mảng các đối tượng tùy chỉnh theo giá trị thuộc tính


521

giả sử chúng ta có một lớp tùy chỉnh có tên imageFile và lớp này chứa hai thuộc tính.

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

rất nhiều trong số chúng được lưu trữ trong 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)

câu hỏi là: làm thế nào tôi có thể sắp xếp mảng hình ảnh theo 'fileID' ASC hoặc DESC?


Câu trả lời:


941

Đầu tiên, khai báo Mảng của bạn dưới dạng một mảng được gõ để bạn có thể gọi các phương thức khi lặp lại:

var images : [imageFile] = []

Sau đó, bạn có thể chỉ cần làm:

Swift 2

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

Swift 3+

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

Ví dụ trên đưa ra thứ tự sắp xếp desc


1
Tôi đã thiếu một phần khai báo mảng, nó đã thực hiện thủ thuật Mảng <imageFile>.
mohacs

1
@AlexWayne Tôi có một NSManagedObjectlớp con gọi là CheckInAndOut . Và trong một tệp riêng biệt, tôi đã khai báo một mảng được gõ cho các đối tượng thuộc loại này và khi tôi cố gắng sắp xếp nó, tôi nhận được lỗi Không thể tìm thấy thành viên . Có ai biết vì sao lại thế này không?
Isuru

3
Tôi tìm thấy vấn đề của tôi. Rõ ràng mảng không phải là một mảng đánh máy. Dù sao tôi có một vấn đề mới. Làm thế nào tôi có thể sắp xếp một mảng theo nhiều thuộc tính? Nói rằng tôi có 2 thuộc tính như firstNamelastNametrong một mảng các Personđối tượng. Đầu tiên tôi muốn sắp xếp nó firstNamevà sau đó lastName. Làm thế nào tôi có thể làm điều này?
Isuru

12
bây giờ bạn cần phải làm gì images.sortInPlace({ $0.fileID > $1.fileID })?
Taylor M

13
trong trường hợp bất cứ ai cũng thắc mắc như vậy: câu trả lời sẽ đưa ra thứ tự desc
Danny Wang

223

[ Đã cập nhật cho Swift 3 với sort (by :) ] Điều này, khai thác một bao đóng dấu:

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

nơi bạn sử dụng <hoặc >tùy thuộc vào ASC hoặc DESC, tương ứng. Nếu bạn muốn sửa đổi imagesmảng , sau đó sử dụng như sau:

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

Nếu bạn định làm điều này nhiều lần và thích xác định hàm, một cách là:

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

và sau đó sử dụng như:

images.sort(by: sorterForFileIDASC)

Làm thế nào tôi có thể kiện này với chuỗi? tôi cần sắp xếp chuỗi theo chiều dài của nó
Muneef M

@MuneefM chỉ cần trả về chuỗi1.length <string2.length
Surjeet Rajput

sortkhông còn biên dịch với cú pháp này trong Xcode 8. Xcode 8 cho biết $0.fileID < $1.fileIDtạo Bool chứ không phải so sánhResult.
Crashalot

3
Mã của câu trả lời này hoạt động tốt trong Xcode8; nếu bạn gặp lỗi, hãy đăng câu hỏi mới.
GoZoner

Tôi cũng có thể sử dụng điều này để sắp xếp theo so sánh, ví dụ như có sắp xếp mảng theo các ngày trong tuần không? nếu vậy thì thế nào?
Kristofer

53

Gần như tất cả mọi người đưa ra cách trực tiếp, hãy để tôi cho thấy sự phát triển:

bạn có thể sử dụng các phương thức thể hiện của 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 })

Để biết giải thích chi tiết về nguyên tắc làm việc của sắp xếp, hãy xem Hàm Sắp xếp .


Tôi cũng có thể sử dụng điều này để sắp xếp theo so sánh, ví dụ như có sắp xếp mảng theo các ngày trong tuần không? nếu vậy thì thế nào?
Kristofer

Cảm ơn bạn đã đăng câu trả lời cho thấy cách đóng cửa hoạt động thay vì giả sử người đọc hiểu cú pháp khó hiểu của việc đóng "đơn giản hóa"!
dùng1118321

50

Swift 3

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

tôi đã thử điều này với một so sánh ngày, không thể làm cho nó hoạt động. Bất kỳ ý tưởng?
Ebru Güngor

Không phải NSDate hoặc String, đối tượng 3 ngày hiện tại nhanh chóng.
Ebru Güngor

Bạn đang so sánh tài sản nào của Date? Tài sản phải có thể được so sánh với chức năng được sử dụng (lớn hơn trong ví dụ của tôi)
tuyệt vời vào

9
Đây là câu trả lời hữu ích duy nhất cho năm 2017 trở đi.
Fattie

@Fattie Ý bạn là gì? Cú pháp đúng làpeople.sort { $0.email > $1.email }
Leo Dabus

43

Với Swift 5, Arraycó hai phương thức được gọi sorted()sorted(by:). Phương thức đầu tiên sorted(), có khai báo sau:

Trả về các phần tử của bộ sưu tập, được sắp xếp.

func sorted() -> [Element]

Phương thức thứ hai sorted(by:), có khai báo sau:

Trả về các phần tử của bộ sưu tập, được sắp xếp bằng cách sử dụng vị từ đã cho làm so sánh giữa các phần tử.

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

# 1. Sắp xếp theo thứ tự tăng dần cho các đối tượng so sánh

Nếu loại phần tử bên trong bộ sưu tập của bạn tuân thủ Comparablegiao thức, bạn sẽ có thể sử dụng sorted()để sắp xếp các phần tử của mình theo thứ tự tăng dần. Mã Playground sau đây cho biết cách sử dụng 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. Sắp xếp theo thứ tự giảm dần cho các đối tượng so sánh

Nếu loại phần tử bên trong bộ sưu tập của bạn tuân thủ Comparablegiao thức, bạn sẽ phải sử dụng sorted(by:)để sắp xếp các phần tử của mình theo thứ tự giảm dần.

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. Sắp xếp theo thứ tự tăng dần hoặc giảm dần cho các đối tượng không thể so sánh

Nếu loại phần tử bên trong bộ sưu tập của bạn KHÔNG tuân thủ Comparablegiao thức, bạn sẽ phải sử dụng sorted(by:)để sắp xếp các phần tử của mình theo thứ tự tăng dần hoặc giảm dần.

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

Lưu ý rằng Swift cũng cung cấp hai phương thức được gọi sort()sort(by:)là đối tác của sorted()sorted(by:)nếu bạn cần sắp xếp bộ sưu tập của mình tại chỗ.


25

Trong Swift 3.0

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

20

Bạn cũng có thể làm một cái gì đó như

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

vì vậy mảng hình ảnh của bạn sẽ được lưu trữ như đã sắp xếp


19

Swift 2 đến 4

Câu trả lời ban đầu đã tìm cách sắp xếp một mảng các đối tượng tùy chỉnh bằng cách sử dụng một số thuộc tính. Dưới đây tôi sẽ chỉ cho bạn một vài cách hữu ích để thực hiện hành vi tương tự với cấu trúc dữ liệu nhanh chóng!

Những điều nhỏ nhặt trên đường đi, tôi đã thay đổi ImageFile một chút. Với ý nghĩ đó, tôi tạo một mảng với ba tệp hình ảnh. Lưu ý rằng siêu dữ liệu là một giá trị tùy chọn, được chuyển đến nil dưới dạng tham số được mong đợi.

 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 có một thuộc tính có tên là kích thước. Đối với các ví dụ sau tôi sẽ chỉ cho bạn cách sử dụng các thao tác sắp xếp với các thuộc tính như kích thước.

kích thước nhỏ nhất đến lớn nhất (<)

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

lớn nhất đến nhỏ nhất (>)

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

Tiếp theo chúng ta sẽ sắp xếp bằng tên thuộc tính String. Theo cách tương tự, sử dụng sắp xếp để so sánh các chuỗi. Nhưng chú ý khối bên trong trả về kết quả so sánh. Kết quả này sẽ xác định sắp xếp.

AZ (.orderedAsceinating)

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

ZA (.orderedDesceinating)

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

Tiếp theo là cách yêu thích của tôi để sắp xếp, trong nhiều trường hợp, người ta sẽ có các thuộc tính tùy chọn. Bây giờ đừng lo lắng, chúng ta sẽ sắp xếp theo cách tương tự như trên trừ khi chúng ta phải xử lý con số không! Trong sản xuất;

Tôi đã sử dụng mã này để buộc tất cả các cá thể trong mảng của mình với các giá trị thuộc tính nil là cuối cùng. Sau đó, đặt hàng siêu dữ liệu bằng cách sử dụng các giá trị chưa được giả định.

    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
    }

Có thể có một loại thứ cấp cho các tùy chọn. Ví dụ; người ta có thể hiển thị hình ảnh với siêu dữ liệu và được sắp xếp theo kích thước.


1
Nói chung, câu trả lời sẽ hữu ích hơn nhiều nếu chúng bao gồm một lời giải thích về những gì mã được dự định làm và tại sao điều đó giải quyết vấn đề mà không giới thiệu người khác.
Tom Aranda

Tốt hơn nhiều
Tom Aranda

18

Hai lựa chọn thay thế

1) Sắp xếp mảng gốc với sortInPlace

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

2) Sử dụng một mảng thay thế để lưu trữ mảng đã ra lệnh

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

3
re 2) Điểm nào trong việc xây dựng một mảng trống và loại bỏ nó trong dòng tiếp theo là gì? Tôi muốn sử dụng var assignmentsO : [Assignment]hoặc kết hợp nó thành một dòng bằng cách sử dụnglet assignmentsO = self.assignments.sort({ $0.order < $1.order })
Hermann Klecker

2
Chào Hermann! Có một ranh giới rất mỏng giữa việc viết mã có thể đọc và hiệu quả. Trong trường hợp này, điểm duy nhất là làm cho cộng đồng dễ đọc hơn;) hãy tận hưởng!
Bernauer

18

Swift 4.0, 4.1 & 4.2 Trước tiên, tôi đã tạo ra mảng biến đổi của kiểu imageFile () như hiển thị bên dưới

var arr = [imageFile]()

Tạo hình ảnh đối tượng có thể thay đổi của kiểu imageFile () và gán giá trị cho các thuộc tính như được hiển thị bên dưới

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

Bây giờ, nối đối tượng này vào mảng mảng

    arr.append(image)

Bây giờ, gán các thuộc tính khác nhau cho cùng một đối tượng có thể thay đổi tức là hình ảnh

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

Bây giờ, một lần nữa nối đối tượng hình ảnh vào mảng mảng

    arr.append(image)

Bây giờ, chúng ta sẽ áp dụng thứ tự tăng dần trên thuộc tính fileId trong các đối tượng mảng mảng. Sử dụng <biểu tượng cho thứ tự tăng dần

 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

Bây giờ, chúng ta sẽ áp dụng thứ tự giảm dần trên thuộc tính fileId trong các đối tượng mảng mảng. Sử dụng biểu tượng cho thứ tự giảm dần

 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

Trong Swift 4.1. & 4.2 Để sử dụng thứ tự sắp xếp

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

8

Nếu bạn sắp xếp mảng này ở nhiều nơi, có thể có nghĩa là làm cho kiểu mảng của bạn có thể so sánh được.

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

Nếu bạn không sử dụng các đối tượng tùy chỉnh, nhưng các loại giá trị thay vào đó thực hiện giao thức so sánh (Int, String, v.v.), bạn có thể chỉ cần làm điều này:

myArray.sort(>) //sort descending order

Một ví dụ:

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

trong swift 3 đó làmyArray.sorted(by: >)
beryllium

6

Bạn trả về một mảng được sắp xếp từ thuộc tính fileID theo cách sau:

Swift 2

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

Swift 3 HOẶC 4

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

Swift 5.0

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

Hoạt động như một sự quyến rũ .. nâng cao! (Pratik Prajapati, Ahmedabad)
NSPratik

4

Tôi làm nó như thế này và nó hoạt động:

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


2

Nếu bạn muốn sắp xếp mảng ban đầu của các đối tượng tùy chỉnh. Đây là một cách khác để làm như vậy trong Swift 2.1

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

Trường hợp idlà một số nguyên. Bạn có thể sử dụng cùng một <toán tử cho Stringcác thuộc tính là tốt.

Bạn có thể tìm hiểu thêm về việc sử dụng nó bằng cách xem một ví dụ ở đây: Swift2: Khách hàng gần đó


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

students.sort(by: >)

print(students)

Bản in: "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"


1

Swift 3 & 4 & 5

Tôi có một số vấn đề liên quan đến chữ thường và chữ hoa

vì vậy tôi đã làm mã này

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

và sau đó sử dụng sortImages sau đó


0

Sắp xếp bằng KeyPath

bạn có thể sắp xếp KeyPathnhư thế này:

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

Bằng cách thực hiện phần mở rộng hữu ích nhỏ này.

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

Hy vọng Swift thêm điều này trong tương lai gần trong cốt lõi của ngôn ngữ.


Điều này đã được trả lời ở đây stackoverflow.com/a/46601105/2303865 cùng với phương pháp đột biến là tốt.
Leo Dabus

phiên bản đột biếnpublic 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.