如何在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'升序或降序?

467710 次浏览

[为Swift 3更新排序(by:)]这,利用一个尾随闭包:

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

你分别根据ASC或DESC使用<>如果你想修改images数组,然后使用以下:

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

如果你要重复这样做,并且更喜欢定义一个函数,一种方法是:

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

然后用as:

images.sort(by: sorterForFileIDASC)

首先,将Array声明为类型化数组,以便在迭代时调用方法:

var images : [imageFile] = []

然后你可以简单地做:

斯威夫特2

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

斯威夫特3 +

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

上面的例子按降序给出了结果。

你也可以这样做

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

你的图像数组会以排序的方式存储

如果你要在多个地方对这个数组排序,让你的数组类型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]"

几乎每个人都直接给出如何,让我展示一下演变:

你可以使用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 })

关于sort的工作原理的详细解释,请参见排序函数

如果你不使用自定义对象,而是使用值类型来实现可比协议(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 5中,Array有两个方法,分别是sorted()sorted(by:)。第一个方法,sorted(),有如下声明:

返回排序后的集合元素。

func sorted() -> [Element]

第二个方法,sorted(by:),有如下声明:

返回集合的元素,使用给定的谓词作为元素之间的比较进行排序。

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

# 1。对可比较的对象进行升序排序

如果集合中的元素类型符合Comparable协议,则可以使用sorted()以升序对元素进行排序。下面的Playground代码展示了如何使用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 { $0 > $1 } // 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 { $0.fileID < $1.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.1中有另一种方法

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

其中id是一个整数。您也可以对String属性使用相同的<操作符。

你可以通过下面的例子了解更多关于它的用法: # EYZ0 < / p >

两个选择

1)使用sortInPlace对原始数组排序

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

2)使用替代数组存储有序数组

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

斯威夫特3

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

在Swift 3.0中

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

我是这样做的,而且很管用:

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

. sort (by: {$0.fileID.compare($1.fileID) == .orderedAscending}

Swift 4.0, 4.1 &4.2:

首先,我创建了imageFile类型的可变数组,如下所示

var arr = [imageFile]()

创建类型为imageFile的可变对象图像,并为属性赋值,如下所示

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

现在,将该对象追加到数组arr

arr.append(image)

现在,将不同的属性分配给同一个可变对象,即image

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

现在,再次将图像对象追加到数组arr

arr.append(image)

现在,我们将在数组arr对象中的fileId属性上应用升序排序。按升序使用& lt;象征

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

现在,我们将在数组arr对象中的fileId属性上应用降序排列。按降序使用>象征

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

在Swift 4.1 &4.2、为排序顺序使用

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

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的属性。对于下面的例子,我将向您展示如何使用排序操作w/属性,如大小。

# EYZ0

    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
}

接下来,我们将使用String属性名进行排序。以同样的方式,使用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!在生产;

我使用这段代码强制数组中具有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
}

可以为可选项设置二级排序。例如;可以显示带有元数据并按大小排序的图像。

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


students.sort(by: >)


print(students)

打印:"["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"

Swift 3 &4,5

我遇到了一些关于小写和大写的问题

所以我写了这个代码

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

然后使用sortedImages

从fileID属性返回一个排序的数组,方法如下:

斯威夫特2

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

Swift 3或4

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

斯威夫特5.0

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

使用KeyPath排序

你可以按KeyPath排序,如下所示:

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

通过实现这个有用的扩展。

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

希望Swift在不久的将来把这个添加到语言的核心中。

如果数组元素符合Comparable,那么你可以简单地使用函数语法:

array.sort(by: <)

如果你是基于自定义类型排序,你所需要做的就是实现<操作符:

class ImageFile {
let fileName: String
let fileID: Int
let fileSize: Int
static func < (left: ImageFile, right: ImageFile) -> Bool {
return left.fileID < right.fileID
}
}

然而,有时您不希望使用一种标准的方式来比较# eyz0。也许在某些情况下,您希望基于fileID对图像进行排序,而在其他情况下,您希望基于fileSize对图像进行排序。对于动态比较,您有两个选项。

sorted(by:)

images = images.sorted(by: { a, b in
// Return true if `a` belongs before `b` in the sorted array
if a.fileID < b.fileID { return true }
if a.fileID > b.fileID { return false }
// Break ties by comparing file sizes
return a.fileSize > b.fileSize
})

你可以使用尾随闭包来简化语法:

images.sorted { ... }

但是手动输入if语句可能会导致很长的代码(如果我们想通过基于文件名排序来打破文件大小的束缚,我们将会有一个相当长的if厄运链)。我们可以通过使用全新的SortComparator协议(macOS 12+, iOS 15+)来避免这种语法:

# EYZ0

files = files.sorted(using: [
KeyPathComparator(\.fileID, order: .forward),
KeyPathComparator(\.fileSize, order: .reverse),
])

这段代码根据文件ID (.forward表示升序)对文件进行排序,并根据文件大小(.reverse表示降序)对文件进行排序。\.fileID语法是我们指定关键路径的方法。您可以根据需要扩展比较器列表。

斯威夫特3、4、5所示

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

//append objects like this
var arrImages = [imageFile]()
arrImages.append(.init(fileName: "Hello1.png", fileID: 1))
arrImages.append(.init(fileName: "Hello3.png", fileID: 3))
arrImages.append(.init(fileName: "Hello2.png",fileID: 2))


    

//array sorting using below code
let sortImagesArr = arrImages.sorted(by: {$0.fileID < $1.fileID})
print(sortImagesArr)
    

//output
    

imageFile(fileName: "Hello1.png", fileID: 1),
imageFile(fileName: "Hello2.png", fileID: 2),
imageFile(fileName: "Hello3.png", fileID: 3)