当前位置: 首页 > 知识库问答 >
问题:

快速排序具有多个标准的对象数组

徐焱
2023-03-14

我有一个联系人对象数组:

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

联系类:

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

我想按lastName然后按firstName对该数组进行排序,以防某些联系人获得相同的lastName

我可以按其中一个标准排序,但不能两个都选。

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

如何添加更多条件来对此数组进行排序?

共有3个答案

公良修竹
2023-03-14

下面显示了使用2个标准进行排序的另一种简单方法。

检查第一个字段,在本例中是姓氏,如果它们不相等,则按姓氏排序,如果姓氏相等,则按第二个字段排序,在本例中为名字

contacts.sort { $0.lastName == $1.lastName ? $0.firstName < $1.firstName : $0.lastName < $1.lastName  }
白博易
2023-03-14

想想“按多个标准排序”是什么意思。这意味着两个对象首先通过一个标准进行比较。然后,如果这些条件相同,领带将被下一个条件打破,以此类推,直到您得到所需的顺序。

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

您在这里看到的是< code > sequence . sorted(by:)方法,它参考提供的闭包来确定元素如何比较。

如果您的排序将在许多地方使用,那么最好使您的类型符合< code>Comparable协议。这样,您可以使用< code>Sequence.sorted()方法,该方法参考您的< code>Comparable的实现。

封烈
2023-03-14

按多个标准执行排序的一种非常简单的方法(即按一个比较进行排序,如果等效,则按另一个比较)是使用元组作为<code>

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

例如:

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")
// ]

这将首先比较元素的< code>lastName属性。如果它们不相等,那么排序顺序将基于< code >

标准库提供了<代码>

如果希望不同的属性有不同的排序顺序,只需交换元组中的元素即可:

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"),
// ]

现在将按<code>lastName</code>降序排序,然后按<code>firstName</ccode>升序排序。

受关于使用<code>map</code>闭包和SortDescriptor对集合进行排序的讨论的启发,另一个选项是定义一个自定义重载<code>sort(by:)</code>和<code>sort(by:),用于处理多个谓词,其中每个谓词依次被考虑以决定元素的顺序。

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

< b>

extension Sequence {
  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
    }
  }
}

第二个谓词:参数很不幸,但为了避免使用现有的排序(by:)重载创建歧义,这是必需的)

然后,这允许我们说(使用前面的联系人数组):

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
  // ...
)

尽管调用站点不像元组变体那样简洁,但您可以进一步清楚地了解要比较的内容以及按什么顺序进行比较。

如果你打算定期进行这种比较,那么,就像@AMomchilov

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

现在只需调用sor()进行升序:

contacts.sort()

或<code>排序(按:

contacts.sort(by: >)

如果您有其他想要使用的排序顺序,您可以在嵌套类型中定义它们:

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

然后简单地调用为:

contacts.sort(by: Contact.Comparison.firstLastAscending)
 类似资料:
  • 假设我们将Quicksort修改为有三个分区,而不是两个分区。左侧分区的值 pivot。然后我们对左分区和右分区进行递归。这个3路分区需要多少时间? 我在一个面试问题中看到了这一点,那里的答案是O(n)。但对于普通的1次快速排序,它是O(nlogn)。 请帮我弄明白为什么不是?

  • 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两

  • 1. 前言 本节内容是排序算法系列之一:快速排序,主要讲解了快速排序的主体思路,选取了一个待排序的数字列表对快速排序算法进行了演示,给出了快速排序算法的 Java 代码实现,帮助大家可以更好地理解快速排序算法。 2. 什么是快速排序? 快速排序(Quick Sort),是计算机科学与技术领域中非常经典的一种排序算法,应用分治思想进行排序。 快速排序由于其时间复杂度优于大部分的排序算法,因而命名为快

  • 我正在寻找一个非常具体的数据结构。假设已知元素的最大数量。所有元素都是整数。允许复制。行动包括: 查阅如果我插入n个元素,是最小的元素,是最高的元素是k个最小的元素。所需运行时间: 插入。执行排序的插入,其中是一个整数。所需的运行时: 删除。删除(i)删除第i个元素。所需的运行时: 我想要一种数据结构,是这样吗?我的问题与语言无关,但我用C语言编写代码。