Swift - Sắp xếp mảng đối tượng với nhiều tiêu chí


91

Tôi có một mảng các Contactđối tượng:

var contacts:[Contact] = [Contact]()

Liên hệ với lớp:

Class Contact:NSOBject {
    var firstName:String!
    var lastName:String!
}

Và tôi muốn sắp xếp mảng lastNameđó theo thứ tự firstNametrong trường hợp một số địa chỉ liên hệ bị giống nhau lastName.

Tôi có thể sắp xếp theo một trong những tiêu chí đó, nhưng không phải cả hai.

contacts.sortInPlace({$0.lastName < $1.lastName})

Làm cách nào để thêm nhiều tiêu chí để sắp xếp mảng này?


2
Hãy làm y như cách bạn vừa nói! Mã của bạn bên trong dấu ngoặc nhọn sẽ nói: "Nếu họ giống nhau, thì hãy sắp xếp theo tên; nếu không thì sắp xếp theo họ".
matt

4
Tôi thấy một vài mã có mùi ở đây: 1) Contactcó lẽ không nên kế thừa từ NSObject, 2) Contactcó lẽ nên là một cấu trúc, và 3) firstNamelastNamecó lẽ không nên là các tùy chọn được bỏ gói ngầm.
Alexander - Khôi phục Monica

3
@AMomchilov Không có lý do gì để đề xuất Liên hệ nên là một cấu trúc bởi vì bạn không biết liệu phần còn lại của mã của anh ấy đã dựa vào ngữ nghĩa tham chiếu khi sử dụng các trường hợp của nó hay chưa.
Patrick Goley

3
@AMomchilov "Có thể" gây hiểu lầm vì bạn không biết chính xác gì về phần còn lại của cơ sở mã. Nếu nó được thay đổi thành cấu trúc, tất cả các bản sao đột ngột sẽ được tạo ra khi thay đổi các vars, thay vì sửa đổi phiên bản hiện tại. Đây là một sự thay đổi mạnh mẽ trong hành vi và làm điều đó "có thể" sẽ dẫn đến lỗi vì không chắc mọi thứ đã được mã hóa đúng cho cả ngữ nghĩa tham chiếu giá trị.
Patrick Goley

1
@AMomchilov Vẫn chưa biết một lý do tại sao nó có lẽ phải là một cấu trúc. Tôi không nghĩ OP sẽ đánh giá cao những đề xuất sửa đổi ngữ nghĩa của phần còn lại của chương trình của anh ấy, đặc biệt là khi nó thậm chí không cần thiết để giải quyết vấn đề trong tầm tay. Đã không nhận ra quy tắc biên dịch là legalese để một số ... có lẽ tôi đang trên trang web sai
Patrick Goley

Câu trả lời:


118

Hãy nghĩ xem "sắp xếp theo nhiều tiêu chí" nghĩa là gì. Có nghĩa là trước tiên hai đối tượng được so sánh theo một tiêu chí. Sau đó, nếu các tiêu chí đó giống nhau, các mối quan hệ sẽ bị phá vỡ bởi các tiêu chí tiếp theo, và cứ tiếp tục như vậy cho đến khi bạn có được thứ tự mong muốn.

let sortedContacts = contacts.sort {
    if $0.lastName != $1.lastName { // first, compare by last names
        return $0.lastName < $1.lastName
    }
    /*  last names are the same, break ties by foo
    else if $0.foo != $1.foo {
        return $0.foo < $1.foo
    }
    ... repeat for all other fields in the sorting
    */
    else { // All other fields are tied, break ties by last name
        return $0.firstName < $1.firstName
    }
}

Những gì bạn đang thấy ở đây là Sequence.sorted(by:)phương thức , tham khảo ý kiến ​​của bao đóng được cung cấp để xác định cách các phần tử so sánh.

Nếu cách sắp xếp của bạn sẽ được sử dụng ở nhiều nơi, thì tốt hơn là bạn nên làm cho kiểu của bạn tuân theo Comparable giao thức . Bằng cách đó, bạn có thể sử dụng Sequence.sorted()phương thức tham vấn việc triển Comparable.<(_:_:)khai toán tử của bạn để xác định cách các phần tử so sánh. Bằng cách này, bạn có thể sắp xếp bất kỳ Sequencecủa Contacts mà không bao giờ phải lặp lại các mã phân loại.


2
Phần elsethân phải nằm giữa { ... }nếu không thì mã không biên dịch.
Luca Angeletti

Hiểu rồi. Tôi đã cố gắng triển khai nó nhưng không thể hiểu đúng cú pháp. Cảm ơn rất nhiều.
sbkl

cho sortvs. sortInPlacexem tại đây . Aslo thấy này dưới đây, đó là nhiều mô-đun hơn
Mật ong

sortInPlaceKHÔNG còn có sẵn trong Swift 3, thay vào đó bạn phải sử dụng nó sort(). sort()sẽ tự thay đổi mảng. Ngoài ra, có một func mới có tên sorted()sẽ trả về một mảng đã được sắp xếp
Honey

2
@AthanasiusOfAlex Sử dụng ==không phải là một ý kiến ​​hay. Nó chỉ hoạt động cho 2 thuộc tính. Bất kỳ hơn thế nữa, và bạn bắt đầu lặp lại chính mình với rất nhiều biểu thức boolean phức tạp
Alexander - Khôi phục Monica

118

Sử dụng bộ giá trị để so sánh nhiều tiêu chí

Một cách thực sự đơn giản để thực hiện sắp xếp theo nhiều tiêu chí (tức là sắp xếp theo một phép so sánh và nếu tương đương thì bằng một phép so sánh khác) là sử dụng các bộ giá trị , vì toán tử <>có quá tải cho chúng để thực hiện so sánh từ vựng.

/// Returns a Boolean value indicating whether the first tuple is ordered
/// before the second in a lexicographical ordering.
///
/// Given two tuples `(a1, a2, ..., aN)` and `(b1, b2, ..., bN)`, the first
/// tuple is before the second tuple if and only if
/// `a1 < b1` or (`a1 == b1` and
/// `(a2, ..., aN) < (b2, ..., bN)`).
public func < <A : Comparable, B : Comparable>(lhs: (A, B), rhs: (A, B)) -> Bool

Ví dụ:

struct Contact {
  var firstName: String
  var lastName: String
}

var contacts = [
  Contact(firstName: "Leonard", lastName: "Charleson"),
  Contact(firstName: "Michael", lastName: "Webb"),
  Contact(firstName: "Charles", lastName: "Alexson"),
  Contact(firstName: "Michael", lastName: "Elexson"),
  Contact(firstName: "Alex", lastName: "Elexson"),
]

contacts.sort {
  ($0.lastName, $0.firstName) <
    ($1.lastName, $1.firstName)
}

print(contacts)

// [
//   Contact(firstName: "Charles", lastName: "Alexson"),
//   Contact(firstName: "Leonard", lastName: "Charleson"),
//   Contact(firstName: "Alex", lastName: "Elexson"),
//   Contact(firstName: "Michael", lastName: "Elexson"),
//   Contact(firstName: "Michael", lastName: "Webb")
// ]

Điều này sẽ so sánh các lastNamethuộc tính của các phần tử đầu tiên. Nếu chúng không bằng nhau, thì thứ tự sắp xếp sẽ dựa trên sự <so sánh với chúng. Nếu họ bằng nhau, sau đó nó sẽ chuyển sang cặp tiếp theo của các nguyên tố trong các tuple, tức là so sánh các firstNamethuộc tính.

Thư viện chuẩn cung cấp <>nạp chồng cho các bộ giá trị từ 2 đến 6 phần tử.

Nếu bạn muốn các thứ tự sắp xếp khác nhau cho các thuộc tính khác nhau, bạn chỉ cần hoán đổi các phần tử trong các bộ giá trị:

contacts.sort {
  ($1.lastName, $0.firstName) <
    ($0.lastName, $1.firstName)
}

// [
//   Contact(firstName: "Michael", lastName: "Webb")
//   Contact(firstName: "Alex", lastName: "Elexson"),
//   Contact(firstName: "Michael", lastName: "Elexson"),
//   Contact(firstName: "Leonard", lastName: "Charleson"),
//   Contact(firstName: "Charles", lastName: "Alexson"),
// ]

Điều này bây giờ sẽ sắp xếp theo lastNamegiảm dần, sau đó firstNametăng dần.


Xác định sort(by:)quá tải có nhiều vị từ

Lấy cảm hứng từ cuộc thảo luận về Sắp xếp Bộ sưu tập với bao mapđóng và Bộ ký hiệu sắp xếp , một tùy chọn khác sẽ là xác định quá tải tùy chỉnh sort(by:)sorted(by:)xử lý nhiều vị từ - trong đó mỗi vị từ được xem xét lần lượt để quyết định thứ tự của các phần tử.

extension MutableCollection where Self : RandomAccessCollection {
  mutating func sort(
    by firstPredicate: (Element, Element) -> Bool,
    _ secondPredicate: (Element, Element) -> Bool,
    _ otherPredicates: ((Element, Element) -> Bool)...
  ) {
    sort(by:) { lhs, rhs in
      if firstPredicate(lhs, rhs) { return true }
      if firstPredicate(rhs, lhs) { return false }
      if secondPredicate(lhs, rhs) { return true }
      if secondPredicate(rhs, lhs) { return false }
      for predicate in otherPredicates {
        if predicate(lhs, rhs) { return true }
        if predicate(rhs, lhs) { return false }
      }
      return false
    }
  }
}

extension Sequence {
  mutating func sorted(
    by firstPredicate: (Element, Element) -> Bool,
    _ secondPredicate: (Element, Element) -> Bool,
    _ otherPredicates: ((Element, Element) -> Bool)...
  ) -> [Element] {
    return sorted(by:) { lhs, rhs in
      if firstPredicate(lhs, rhs) { return true }
      if firstPredicate(rhs, lhs) { return false }
      if secondPredicate(lhs, rhs) { return true }
      if secondPredicate(rhs, lhs) { return false }
      for predicate in otherPredicates {
        if predicate(lhs, rhs) { return true }
        if predicate(rhs, lhs) { return false }
      }
      return false
    }
  }
}

( secondPredicate:Tham số là không may, nhưng được yêu cầu để tránh tạo ra sự mơ hồ với sort(by:)tình trạng quá tải hiện có )

Sau đó, điều này cho phép chúng tôi nói (sử dụng contactsmảng trước đó):

contacts.sort(by:
  { $0.lastName > $1.lastName },  // first sort by lastName descending
  { $0.firstName < $1.firstName } // ... then firstName ascending
  // ...
)

print(contacts)

// [
//   Contact(firstName: "Michael", lastName: "Webb")
//   Contact(firstName: "Alex", lastName: "Elexson"),
//   Contact(firstName: "Michael", lastName: "Elexson"),
//   Contact(firstName: "Leonard", lastName: "Charleson"),
//   Contact(firstName: "Charles", lastName: "Alexson"),
// ]

// or with sorted(by:)...
let sortedContacts = contacts.sorted(by:
  { $0.lastName > $1.lastName },  // first sort by lastName descending
  { $0.firstName < $1.firstName } // ... then firstName ascending
  // ...
)

Mặc dù call-site không ngắn gọn như biến thể tuple, nhưng bạn sẽ hiểu rõ hơn về những gì đang được so sánh và theo thứ tự.


Tuân theo Comparable

Nếu bạn đang đi để được làm các loại so sánh thường xuyên sau đó, như @AMomchilov & @appzYourLife gợi ý, bạn có thể phù hợp Contactđể Comparable:

extension Contact : Comparable {
  static func == (lhs: Contact, rhs: Contact) -> Bool {
    return (lhs.firstName, lhs.lastName) ==
             (rhs.firstName, rhs.lastName)
  }

  static func < (lhs: Contact, rhs: Contact) -> Bool {
    return (lhs.lastName, lhs.firstName) <
             (rhs.lastName, rhs.firstName)
  }
}

Và bây giờ chỉ cần gọi sort()cho một đơn đặt hàng tăng dần:

contacts.sort()

hoặc sort(by: >)cho một thứ tự giảm dần:

contacts.sort(by: >)

Xác định thứ tự sắp xếp tùy chỉnh trong một loại lồng nhau

Nếu bạn có các thứ tự sắp xếp khác mà bạn muốn sử dụng, bạn có thể xác định chúng theo kiểu lồng nhau:

extension Contact {
  enum Comparison {
    static let firstLastAscending: (Contact, Contact) -> Bool = {
      return ($0.firstName, $0.lastName) <
               ($1.firstName, $1.lastName)
    }
  }
}

và sau đó chỉ cần gọi là:

contacts.sort(by: Contact.Comparison.firstLastAscending)

contacts.sort { ($0.lastName, $0.firstName) < ($1.lastName, $1.firstName) } Đã giúp đỡ. Cảm ơn
Prabhakar Kasi

Nếu như tôi, các thuộc tính được sắp xếp là optionals, sau đó bạn có thể làm một cái gì đó như thế này: contacts.sort { ($0.lastName ?? "", $0.firstName ?? "") < ($1.lastName ?? "", $1.firstName ?? "") }.
BobCowe 19/09/19

Holly molly! Rất đơn giản nhưng rất hiệu quả ... tại sao tôi chưa bao giờ nghe nói về điều đó ?! Cảm ơn rất nhiều!
Ethenyl

@BobCowe Điều đó khiến bạn phải lo lắng về cách ""so sánh với các chuỗi khác (nó đứng trước các chuỗi không rỗng). Đó là một loại ma thuật ngầm, đại loại và không linh hoạt nếu bạn muốn chữ nils ở cuối danh sách. Tôi khuyên bạn nên xem qua nilComparatorhàm stackoverflow.com/a/44808567/3141234
Alexander - Phục hồi Monica

18

Một cách tiếp cận đơn giản khác để sắp xếp với 2 tiêu chí được hiển thị bên dưới.

Kiểm tra trường đầu tiên, trong trường hợp này là lastName, nếu chúng không bằng nhau, hãy sắp xếp theo lastName, nếu lastName's bằng nhau, thì hãy sắp xếp theo trường thứ hai, trong trường hợp này firstName.

contacts.sort { $0.lastName == $1.lastName ? $0.firstName < $1.firstName : $0.lastName < $1.lastName  }

Điều này mang lại sự linh hoạt hơn so với bộ giá trị.
Babac

5

Một điều mà các sắp xếp từ vựng không thể làm như mô tả của @Hamish là xử lý các hướng sắp xếp khác nhau, chẳng hạn như sắp xếp theo trường đầu tiên giảm dần, trường tiếp theo tăng dần, v.v.

Tôi đã tạo một bài đăng trên blog về cách thực hiện điều này trong Swift 3 và giữ cho mã đơn giản và dễ đọc.

Bạn có thể tìm thấy nó ở đây:

http://master-method.com/index.php/2016/11/23/sort-a-sequence-ie-arrays-of-objects-by-multiple-properties-in-swift-3/

Bạn cũng có thể tìm thấy kho lưu trữ GitHub với mã tại đây:

https://github.com/jallauca/SortByMultipleFieldsSwift.playground

Ý chính của tất cả, giả sử, nếu bạn có danh sách các vị trí, bạn sẽ có thể làm điều này:

struct Location {
    var city: String
    var county: String
    var state: String
}

var locations: [Location] {
    return [
        Location(city: "Dania Beach", county: "Broward", state: "Florida"),
        Location(city: "Fort Lauderdale", county: "Broward", state: "Florida"),
        Location(city: "Hallandale Beach", county: "Broward", state: "Florida"),
        Location(city: "Delray Beach", county: "Palm Beach", state: "Florida"),
        Location(city: "West Palm Beach", county: "Palm Beach", state: "Florida"),
        Location(city: "Savannah", county: "Chatham", state: "Georgia"),
        Location(city: "Richmond Hill", county: "Bryan", state: "Georgia"),
        Location(city: "St. Marys", county: "Camden", state: "Georgia"),
        Location(city: "Kingsland", county: "Camden", state: "Georgia"),
    ]
}

let sortedLocations =
    locations
        .sorted(by:
            ComparisonResult.flip <<< Location.stateCompare,
            Location.countyCompare,
            Location.cityCompare
        )

1
"Một trong những điều các loại hoặc null không thể làm như mô tả của @Hamish là để xử lý hướng sắp xếp khác nhau" - vâng họ có thể, chỉ cần trao đổi các yếu tố trong các tuple;)
Hamish

Tôi thấy đây là một bài tập lý thuyết thú vị nhưng phức tạp hơn nhiều so với câu trả lời của @ Hamish. Ít mã hơn là mã tốt hơn theo quan điểm của tôi.
Manuel

5

Câu hỏi này đã có rất nhiều câu trả lời tuyệt vời, nhưng tôi muốn chỉ ra một bài báo - Sắp xếp mô tả trong Swift . Chúng tôi có một số cách để thực hiện việc sắp xếp nhiều tiêu chí.

  1. Sử dụng NSSortDescriptor, cách này có một số hạn chế, đối tượng phải là một lớp và kế thừa từ NSObject.

    class Person: NSObject {
        var first: String
        var last: String
        var yearOfBirth: Int
        init(first: String, last: String, yearOfBirth: Int) {
            self.first = first
            self.last = last
            self.yearOfBirth = yearOfBirth
        }
    
        override var description: String {
            get {
                return "\(self.last) \(self.first) (\(self.yearOfBirth))"
            }
        }
    }
    
    let people = [
        Person(first: "Jo", last: "Smith", yearOfBirth: 1970),
        Person(first: "Joe", last: "Smith", yearOfBirth: 1970),
        Person(first: "Joe", last: "Smyth", yearOfBirth: 1970),
        Person(first: "Joanne", last: "smith", yearOfBirth: 1985),
        Person(first: "Joanne", last: "smith", yearOfBirth: 1970),
        Person(first: "Robert", last: "Jones", yearOfBirth: 1970),
    ]

    Ví dụ ở đây, chúng ta muốn sắp xếp theo họ, sau đó là tên, cuối cùng là theo năm sinh. Và chúng tôi muốn làm điều đó một cách thiếu tế nhị và sử dụng ngôn ngữ của người dùng.

    let lastDescriptor = NSSortDescriptor(key: "last", ascending: true,
      selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
    let firstDescriptor = NSSortDescriptor(key: "first", ascending: true, 
      selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
    let yearDescriptor = NSSortDescriptor(key: "yearOfBirth", ascending: true)
    
    
    
    (people as NSArray).sortedArray(using: [lastDescriptor, firstDescriptor, yearDescriptor]) 
    // [Robert Jones (1970), Jo Smith (1970), Joanne smith (1970), Joanne smith (1985), Joe Smith (1970), Joe Smyth (1970)]
  2. Sử dụng Swift cách sắp xếp theo họ / tên. Cách này sẽ hoạt động với cả class / struct. Tuy nhiên, chúng tôi không sắp xếp theo nămOfBirth ở đây.

    let sortedPeople = people.sorted { p0, p1 in
        let left =  [p0.last, p0.first]
        let right = [p1.last, p1.first]
    
        return left.lexicographicallyPrecedes(right) {
            $0.localizedCaseInsensitiveCompare($1) == .orderedAscending
        }
    }
    sortedPeople // [Robert Jones (1970), Jo Smith (1970), Joanne smith (1985), Joanne smith (1970), Joe Smith (1970), Joe Smyth (1970)]
  3. Cách nhanh chóng để bắt chước NSSortDescriptor. Điều này sử dụng khái niệm rằng 'các hàm là một loại hạng nhất'. SortDescriptor là một kiểu hàm, nhận hai giá trị, trả về bool. Nói sortByFirstName, chúng tôi lấy hai tham số ($ 0, $ 1) và so sánh tên của chúng. Các hàm kết hợp lấy một loạt các SortDescriptor, so sánh tất cả chúng và đưa ra thứ tự.

    typealias SortDescriptor<Value> = (Value, Value) -> Bool
    
    let sortByFirstName: SortDescriptor<Person> = {
        $0.first.localizedCaseInsensitiveCompare($1.first) == .orderedAscending
    }
    let sortByYear: SortDescriptor<Person> = { $0.yearOfBirth < $1.yearOfBirth }
    let sortByLastName: SortDescriptor<Person> = {
        $0.last.localizedCaseInsensitiveCompare($1.last) == .orderedAscending
    }
    
    func combine<Value>
        (sortDescriptors: [SortDescriptor<Value>]) -> SortDescriptor<Value> {
        return { lhs, rhs in
            for isOrderedBefore in sortDescriptors {
                if isOrderedBefore(lhs,rhs) { return true }
                if isOrderedBefore(rhs,lhs) { return false }
            }
            return false
        }
    }
    
    let combined: SortDescriptor<Person> = combine(
        sortDescriptors: [sortByLastName,sortByFirstName,sortByYear]
    )
    people.sorted(by: combined)
    // [Robert Jones (1970), Jo Smith (1970), Joanne smith (1970), Joanne smith (1985), Joe Smith (1970), Joe Smyth (1970)]

    Điều này là tốt vì bạn có thể sử dụng nó với cả struct và class, thậm chí bạn có thể mở rộng nó để so sánh với nils.

Tuy nhiên, đọc bài báo gốc rất được khuyến khích. Nó có nhiều chi tiết hơn và được giải thích rõ ràng.


2

Tôi khuyên bạn nên sử dụng giải pháp tuple của Hamish vì nó không yêu cầu mã bổ sung.


Nếu bạn muốn thứ gì đó hoạt động giống như các ifcâu lệnh nhưng đơn giản hóa logic phân nhánh, bạn có thể sử dụng giải pháp này, cho phép bạn thực hiện những việc sau:

animals.sort {
  return comparisons(
    compare($0.family, $1.family, ascending: false),
    compare($0.name, $1.name))
}

Dưới đây là các chức năng cho phép bạn làm điều này:

func compare<C: Comparable>(_ value1Closure: @autoclosure @escaping () -> C, _ value2Closure: @autoclosure @escaping () -> C, ascending: Bool = true) -> () -> ComparisonResult {
  return {
    let value1 = value1Closure()
    let value2 = value2Closure()
    if value1 == value2 {
      return .orderedSame
    } else if ascending {
      return value1 < value2 ? .orderedAscending : .orderedDescending
    } else {
      return value1 > value2 ? .orderedAscending : .orderedDescending
    }
  }
}

func comparisons(_ comparisons: (() -> ComparisonResult)...) -> Bool {
  for comparison in comparisons {
    switch comparison() {
    case .orderedSame:
      continue // go on to the next property
    case .orderedAscending:
      return true
    case .orderedDescending:
      return false
    }
  }
  return false // all of them were equal
}

Nếu bạn muốn kiểm tra nó, bạn có thể sử dụng mã bổ sung này:

enum Family: Int, Comparable {
  case bird
  case cat
  case dog

  var short: String {
    switch self {
    case .bird: return "B"
    case .cat: return "C"
    case .dog: return "D"
    }
  }

  public static func <(lhs: Family, rhs: Family) -> Bool {
    return lhs.rawValue < rhs.rawValue
  }
}

struct Animal: CustomDebugStringConvertible {
  let name: String
  let family: Family

  public var debugDescription: String {
    return "\(name) (\(family.short))"
  }
}

let animals = [
  Animal(name: "Leopard", family: .cat),
  Animal(name: "Wolf", family: .dog),
  Animal(name: "Tiger", family: .cat),
  Animal(name: "Eagle", family: .bird),
  Animal(name: "Cheetah", family: .cat),
  Animal(name: "Hawk", family: .bird),
  Animal(name: "Puma", family: .cat),
  Animal(name: "Dalmatian", family: .dog),
  Animal(name: "Lion", family: .cat),
]

Sự khác biệt chính so với giải pháp của Jamie là quyền truy cập vào các thuộc tính được định nghĩa nội tuyến chứ không phải là các phương thức static / instance trên lớp. Ví dụ: $0.familythay vì Animal.familyCompare. Và tăng dần / giảm dần được điều khiển bởi một tham số thay vì một toán tử quá tải. Giải pháp của Jamie thêm một tiện ích mở rộng trên Array trong khi giải pháp của tôi sử dụng phương thức sort/ tích hợp sẵn sortednhưng yêu cầu xác định thêm hai phương thức bổ sung: comparecomparisons.

Vì lợi ích hoàn chỉnh, đây là cách giải pháp của tôi so với giải pháp tuple của Hamish . Để chứng minh, tôi sẽ sử dụng một ví dụ hoang dã trong đó chúng tôi muốn sắp xếp mọi người theo (name, address, profileViews)giải pháp của Hamish sẽ đánh giá từng giá trị trong số 6 giá trị thuộc tính chính xác một lần trước khi bắt đầu so sánh. Điều này có thể không hoặc có thể không được mong muốn. Ví dụ, giả sử profileViewslà một cuộc gọi mạng đắt tiền, chúng tôi có thể muốn tránh gọi profileViewstrừ khi thực sự cần thiết. Giải pháp của tôi sẽ tránh đánh giá profileViewscho đến khi $0.name == $1.name$0.address == $1.address. Tuy nhiên, khi nó đánh giá profileViewsnó có thể sẽ đánh giá nhiều lần hơn một lần.


1

Làm thế nào về:

contacts.sort() { [$0.last, $0.first].lexicographicalCompare([$1.last, $1.first]) }

lexicographicallyPrecedesyêu cầu tất cả các kiểu trong mảng phải giống nhau. Ví dụ [String, String]. Điều OP có thể muốn là trộn và kết hợp các loại: [String, Int, Bool]vì vậy họ có thể làm [$0.first, $0.age, $0.isActive].
Senseful

-1

điều đó đã hoạt động cho mảng [Chuỗi] của tôi trong Swift 3 và có vẻ như trong Swift 4 thì ổn

array = array.sorted{$0.compare($1, options: .numeric) == .orderedAscending}

Bạn đã đọc câu hỏi trước khi trả lời? Sắp xếp theo nhiều tham số, không phải một, những gì bạn trình bày.
Vive
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.