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

moh*_*acs 474 arrays sorting swift

假设我们有一个名为imageFile的自定义类,该类包含两个属性.

class imageFile  {
    var fileName = String()
    var fileID = Int()
}
Run Code Online (Sandbox Code Playgroud)

很多都存储在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)
Run Code Online (Sandbox Code Playgroud)

问题是:如何通过'fileID'ASC或DESC对图像数组进行排序?

Ale*_*yne 864

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

var images : [imageFile] = []
Run Code Online (Sandbox Code Playgroud)

然后你可以简单地做:

斯威夫特2

images.sorted({ $0.fileID > $1.fileID })
Run Code Online (Sandbox Code Playgroud)

斯威夫特3和4

images.sorted(by: { $0.fileID > $1.fileID })
Run Code Online (Sandbox Code Playgroud)

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

  • 如果有人想知道相同:答案将给出desc命令 (13认同)
  • 你现在需要做```images.sortInPlace({$ 0.fileID> $ 1.fileID})```? (12认同)
  • 我发现了我的问题.显然这个数组不是一个类型化的数组.无论如何,我有一个新问题.如何通过多个属性对数组进行排序?假设我在`Person`对象数组中有2个属性,如`firstName`和`lastName`.首先,我想用`firstName`然后`lastName`对它进行排序.我怎么能这样做? (3认同)

GoZ*_*ner 208

[ 更新了Swift 3 with sort(by :) ]这个,利用了一个尾随的闭包:

images.sorted { $0.fileID < $1.fileID }
Run Code Online (Sandbox Code Playgroud)

你在哪里使用<>依赖于ASC或DESC. 如果要修改images阵列,请使用以下命令:

images.sort { $0.fileID < $1.fileID }
Run Code Online (Sandbox Code Playgroud)

如果您要反复执行此操作并且更喜欢定义函数,则一种方法是:

func sorterForFileIDASC(this:imageFile, that:imageFile) -> Bool {
  return this.fileID > that.fileID
}
Run Code Online (Sandbox Code Playgroud)

然后用作:

images.sort(by: sorterForFileIDASC)
Run Code Online (Sandbox Code Playgroud)

  • 这个答案的代码在Xcode8中运行良好; 如果您有错误,请发布一个新问题. (3认同)

fuj*_*471 51

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

你可以使用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 })
Run Code Online (Sandbox Code Playgroud)

有关sort的工作原理的详细说明,请参阅排序函数.


que*_*ful 44

斯威夫特3

people = people.sorted(by: { $0.email > $1.email })
Run Code Online (Sandbox Code Playgroud)

  • **这是2017年以后唯一有用的答案.** (9认同)

Ima*_*tit 38

使用Swift 4,Array有两种方法叫做sorted()sorted(by:).第一种方法sorted()有以下声明:

返回集合的元素,已排序.

func sorted() -> [Element]
Run Code Online (Sandbox Code Playgroud)

第二种方法sorted(by:)有以下声明:

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

func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
Run Code Online (Sandbox Code Playgroud)

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]
 */
Run Code Online (Sandbox Code Playgroud)

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]
 */
Run Code Online (Sandbox Code Playgroud)

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]
 */
Run Code Online (Sandbox Code Playgroud)

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

  • 这是一个很好的答案!非常感谢! (2认同)

jai*_*jan 23

在Swift 3.0中

images.sort(by: { (first: imageFile, second: imageFile) -> Bool in
    first. fileID < second. fileID
})
Run Code Online (Sandbox Code Playgroud)


Ber*_*uer 18

两种选择

1)使用sortInPlace排序原始数组

self.assignments.sortInPlace({ $0.order < $1.order })
self.printAssignments(assignments)
Run Code Online (Sandbox Code Playgroud)

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

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

  • re 2)构建一个空数组并在下一行中丢弃它有什么意义?我使用`var assignmentsO:[Assignment]`或使用`let assignmentsO = self.assignments.sort({$ 0.order <$ 1.order})将它组合成一行. (3认同)
  • 嗨赫尔曼!在编写可读和有效代码之间有一条很细的界限.在这种情况下,唯一的一点是让它对社区更具可读性;)享受! (2认同)

jnb*_*ard 18

斯威夫特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) ]
Run Code Online (Sandbox Code Playgroud)

ImageFile有一个名为size的属性.对于以下示例,我将向您展示如何使用具有大小等属性的排序操作.

最小到最大尺寸(<)

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

从最小到最小(>)

    let sizeBiggestSorted = images.sorted { (initial, next) -> Bool in
      return initial.size > next.size
    }
Run Code Online (Sandbox Code Playgroud)

接下来,我们将使用String属性名称进行排序.以相同的方式,使用sort来比较字符串.但请注意内部块返回比较结果.此结果将定义排序.

AZ(.orderedAscending)

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

ZA(.orderedDescending)

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

接下来是我最喜欢的排序方式,在很多情况下,会有一个可选的属性.现在不用担心,我们将按照与上面相同的方式进行排序,除非我们必须处理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
    }
Run Code Online (Sandbox Code Playgroud)

可以对选项进行二次排序.例如; 可以显示带有元数据的图像并按大小排序.


Nic*_*nié 17

你也可以这样做

images = sorted(images) {$0.fileID > $1.fileID}
Run Code Online (Sandbox Code Playgroud)

所以你的图像数组将被存储为已排序


Gur*_*ngh 15

Swift 4.0,4.1和4.2首先,我创建了类型为imageFile()的可变数组,如下所示

var arr = [imageFile]()
Run Code Online (Sandbox Code Playgroud)

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

   var image = imageFile()
   image.fileId = 14
   image.fileName = "A"
Run Code Online (Sandbox Code Playgroud)

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

    arr.append(image)
Run Code Online (Sandbox Code Playgroud)

现在,将不同的属性分配给相同的可变对象,即图像

   image = imageFile()
   image.fileId = 13
   image.fileName = "B"
Run Code Online (Sandbox Code Playgroud)

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

    arr.append(image)
Run Code Online (Sandbox Code Playgroud)

现在,我们将在数组arr对象的fileId属性上应用升序.使用<符号升序

 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
Run Code Online (Sandbox Code Playgroud)

现在,我们将在数组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
Run Code Online (Sandbox Code Playgroud)

在Swift 4.1中.&4.2对于分类订单使用

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


McK*_*ley 14

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

array.sort(by: <)
Run Code Online (Sandbox Code Playgroud)

如果您根据自定义类型进行排序,您所需要做的就是实现<运算符:

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

但是,有时您不需要一种标准的比较方法ImageFile。也许在某些情况下您希望根据 来对图像进行排序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
})
Run Code Online (Sandbox Code Playgroud)

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

images.sorted { ... }
Run Code Online (Sandbox Code Playgroud)

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

sorted(using:)

files = files.sorted(using: [
    KeyPathComparator(\.fileID, order: .forward),
    KeyPathComparator(\.fileSize, order: .reverse),
])
Run Code Online (Sandbox Code Playgroud)

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

  • 这个答案是唯一一个强调“KeyPathComparator”功能的答案,应该固定。 (6认同)

小智 10

您可以通过以下方式从 fileID 属性返回一个排序数组:

斯威夫特 2

let sortedArray = images.sorted({ $0.fileID > $1.fileID })
Run Code Online (Sandbox Code Playgroud)

斯威夫特 3 或 4

let sortedArray = images.sorted(by: { $0.fileID > $1.fileID })
Run Code Online (Sandbox Code Playgroud)

斯威夫特 5.0

let sortedArray = images.sorted {
    $0.fileID < $1.fileID
}
Run Code Online (Sandbox Code Playgroud)


kwe*_*rle 7

如果您要在多个位置对此数组进行排序,那么使您的数组类型可比较是有意义的.

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]"
Run Code Online (Sandbox Code Playgroud)


dor*_*ian 6

如果您不使用自定义对象,而是使用值类型来实现Comparable协议(Int,String等..),您可以简单地执行此操作:

myArray.sort(>) //sort descending order
Run Code Online (Sandbox Code Playgroud)

一个例子:

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
Run Code Online (Sandbox Code Playgroud)


Pri*_*tel 6

斯威夫特 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)
Run Code Online (Sandbox Code Playgroud)


Ill*_*rit 5

我这样做并且有效:

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