Swift如何按属性值对自定义对象数组进行排序


519

可以说我们有一个名为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” ASC或DESC对图像数组进行排序?


Answers:


939

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

var images : [imageFile] = []

然后,您可以简单地执行以下操作:

迅捷2

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

迅捷3+

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

上面的示例给出了desc排序顺序


1
我缺少数组声明部分,它完成了Array <imageFile>的技巧。
mohacs 2014年

1
@AlexWayne我有一个NSManagedObject名为CheckInAndOut的子类。在一个单独的文件中,我为该类型的对象声明了类型化数组,当我尝试对其进行排序时,出现“找不到成员”错误。知道为什么会这样吗?
Isuru

3
我发现了问题。显然,该数组不是类型化数组。无论如何,我有一个新问题。如何按多个属性对数组排序?假设我有2个属性,例如firstNamelastNamePerson对象数组中。首先,我想按它排序firstName,然后lastName。我该怎么做?
Isuru 2014年

12
您现在需要做images.sortInPlace({ $0.fileID > $1.fileID })什么?
泰勒M

13
如果你想知道的一样:答案会给倒序
丹尼王

223

[ 更新了Swift 3的sort(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
}

然后用作:

images.sort(by: sorterForFileIDASC)

我怎么能用字符串起诉呢?我需要按其长度对字符串进行排序
Muneef M 2015年

@MuneefM只返回string1.length <string2.length
Surjeet Rajput,

sort不再在Xcode 8中使用此语法进行编译。Xcode 8表示$0.fileID < $1.fileID生成的是Bool而不是CompareResult。
Crashalot

3
这个答案的代码在Xcode8中可以正常工作。如果有错误,请发布新问题。
GoZoner

我是否还可以使用它通过比较进行排序,例如按星期几对数组进行排序?如果是这样怎么办?
克里斯托弗

53

几乎每个人都给出直接的方式,让我展示一下演变过程:

您可以使用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的工作原理的详细说明,请参见Sorted Function


我是否还可以使用它通过比较进行排序,例如按星期几对数组进行排序?如果是这样怎么办?
克里斯托弗

感谢您发布的答案显示了闭包的工作原理,而不是假设读者理解“简化”闭包的神秘语法!
user1118321 '19

50

迅捷3

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

我已经尝试过使用日期比较功能,但无法正常工作。任何的想法?
EbruGüngör16年

不是NSDate或String,当前为swift 3 Date对象。
EbruGüngör16年

您要比较Date的哪个属性?该属性必须能够与所使用的函数进行比较(比我的示例更大)
2016年

9
这是2017年以后唯一有用的答案。
Fattie

@Fattie是什么意思?正确的语法是people.sort { $0.email > $1.email }
Leo Dabus

43

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

需要注意的是斯威夫特还提供了两种方法称为sort()sort(by:)作为同行sorted()sorted(by:),如果你需要到您的收藏就地进行排序。




19

迅捷2到4

原始答案试图使用某些属性对自定义对象数组进行排序。下面,我将向您展示一些使用快速数据结构来实现相同行为的便捷方法!

小事情无法解决,我对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的属性。对于以下示例,我将向您展示如何使用带有大小等属性的排序操作。

最小到最大尺寸(<)

    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比较字符串。但是请注意,内部块返回比较结果。该结果将定义排序。

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
    }

接下来是我最喜欢的排序方式,在许多情况下,它将具有可选属性。现在不用担心,除了必须处理nil之外,我们将以与上述相同的方式进行排序!生产中;

我使用此代码强制将数组中具有nil属性值的所有实例都设为last。然后使用假定的未包装值对元数据进行排序。

    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
    }

可以对辅助选项进行辅助排序。例如; 一个可以显示带有元数据并按大小排序的图像。


1
通常,如果答案包括对代码意图的解释,以及为什么不引入其他代码就能解决问题的原因,则答案会更有帮助。
汤姆·阿兰达

好多了。
汤姆·阿兰达

18

两种选择

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
re 2)构造一个空数组并在下一行将其丢弃有什么意义?我建议使用var assignmentsO : [Assignment]或将其合并为一行let assignmentsO = self.assignments.sort({ $0.order < $1.order })
Hermann Klecker,2016年

2
嗨,赫尔曼!在编写可读和高效的代码之间有一条很细的界限。在这种情况下,唯一的一点就是使它对社区更具可读性;)尽情享受!
Bernauer

18

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 = imageFile()
   image.fileId = 13
   image.fileName = "B"

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

    arr.append(image)

现在,我们将应用升序的fileid财产阵列ARR的对象。使用<符号升序

 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

现在,我们将申请降序FILEID财产阵列ARR的对象。使用>符号降序

 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
}

8

如果要在一个以上的地方对该数组进行排序,则使数组类型为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]"

6

如果您不使用自定义对象,而是使用实现可比较协议的值类型(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

在迅速3它是myArray.sorted(by: >)

6

通过以下方式从fileID属性返回排序后的数组:

迅捷2

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

迅捷3或4

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

斯威夫特5.0

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

像魅力一样..赞!(艾哈迈达巴
德普拉蒂普拉贾帕蒂


2

如果要对自定义对象的原始数组进行排序。这是Swift 2.1中执行此操作的另一种方法

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

id整数在哪里。您也可以<String属性使用相同的运算符。

您可以通过以下示例了解有关其用法的更多信息: Swift2:附近的客户


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

students.sort(by: >)

print(students)

版画: "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"



0

使用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在不久的将来将其添加到语言的核心中。


这已经在此处stackoverflow.com/a/46601105/2303865 以及变异方法中得到了解答。
Leo Dabus

变异版本public 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.