【问题标题】:Swift Set Array custom sortSwift Set Array 自定义排序
【发布时间】:2017-06-21 17:02:25
【问题描述】:

我有联系人模型,我想通过[firstLetter, fullName] 对 UITableView 进行排序,这样"FAVORITES" 在 startIndex,"#" 在 endIndex,它们之间是排序的字母。 例如:["A", "C", "E", "#", "FAVORITES"] 变成["FAVORITES", "A", "C", "E", "#"]

这是模型

class Contact: Object {
    dynamic var fullName = ""
    dynamic var firstLetter = ""
}

这是 UITableViewController,我在这里对数据进行排序

class ContactsController: UITableViewController {

    // some code

    var contacts = try! Realm().objects(Contact.self).filter("isDeleted == false").sorted(by: ["firstLetter","fullName"])
    var sections: [String] {
        return Set(contacts.value(forKeyPath: "firstLetter") as![String]).sorted()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        setUI()
    }

    // another code
}

编辑#1


抱歉,我忘了说“#”包含全名以特殊字符开头的联系人

回答我的问题


var sections: [String] {
        return Set(contacts.value(forKeyPath: "firstLetter") as![String]).sorted {
            //Favourites sorts before all else
            if $0 == "FAVORITES" { return true }
            if $1 == "FAVORITES" { return false }

            // Symbols sort after all else
            if $0 == "#" { return false }
            if $1 == "#" { return true }

            return $0 < $1
        }
    }

【问题讨论】:

  • 为什么不将属性 isFavorite 添加到联系人。然后有两个数组用于收藏夹和非收藏夹。按字母排序,然后将它们连接起来。
  • 感谢您的建议。那么“#”呢,我存储以特殊字符开头的联系人?我认为这是一个不好的做法。
  • @SahandTheGreat,如果您将isFavorite 属性添加到Contact,则不需要两个单独的数组,因为您可以像contacts.filter{ $0.isFavorite } 一样过滤它们或contacts.filter{ !$0.isFavorite }.
  • 如果Contact 已经在fullName 中,为什么要存储第一个字母?
  • @Alexander 这很奇怪,但是 Realm 不支持非拉丁字符串的大小写忽略,所以我将 fullName 的第一个字母转换为 upperCase() 以在任何情况下都相似

标签: ios arrays swift sorting


【解决方案1】:

我会这样做。出于测试目的,我不得不更改数据结构,但您可以将其更改回继承自 Object 的类。

public extension Sequence {
    public typealias Element = Iterator.Element
    public typealias Group = [Element]

    public func group<Key: Hashable>(by deriveKey: (Element) -> Key) -> [Key: Group] {
        var groups =  [Key: Group]()

        for element in self {
            let key = deriveKey(element)

            if var existingArray = groups[key] { // Group already exists for this key
                groups[key] = nil //performance optimisation to prevent CoW
                existingArray.append(element)
                groups[key] = existingArray
            }
            else {
                groups[key] = [element] // Create new group
            }
        }

        return groups
    }
}


struct Contact: CustomStringConvertible {
    let fullName: String
    let isFavourte: Bool

    var firstLetter: Character {
        return fullName.characters.first!
    }

    var containsSpecialLetters: Bool {
        return false // implement me
    }

    init(_ fullName: String, _ isFavourte: Bool) {
        self.fullName = fullName
        self.isFavourte = isFavourte
    }

    var description: String { return fullName }
}

let contacts = [
    Contact("Alice", false),
    Contact("Alex", false),
    Contact("Bob", true),
    Contact("Bill", false),
    Contact("Cory", false),
    Contact("Casey", true),
    Contact("#åœ∑´ß", false),
    Contact("D", false),
    Contact("E", false),
    Contact("F", false),
    Contact("G", false),
    Contact("H", false),
]


let sections = contacts.group{ contact -> String in
    switch contact {
        case _ where contact.isFavourte: return "Favourites"
        case _ where contact.containsSpecialLetters: return "#"
        case _: return String(contact.firstLetter)
    }
}

let sectionHeaders = sections.keys.sorted {
    //Favourites sorts before all else
    if $0 == "Favourites" { return true }
    if $1 == "Favourites" { return false }

    // Symbols sort after all else
    if $0 == "#" { return false }
    if $1 == "#" { return true }

    return $0 < $1
}

for (sectionHeader, sectionContacts) in sectionHeaders.map({($0, sections[$0]!)}) {
    print("===== \(sectionHeader) =====")
    sectionContacts.forEach{ print($0) }
}

输出:

===== 收藏夹=====

鲍勃

凯西

===== A =====

爱丽丝

亚历克斯

===== B =====

比尔

===== C =====

科里

===== D =====

D

===== E =====

E

===== F =====

F

===== G =====

G

===== H =====

H

===== # =====

åœ∑´ß

【讨论】:

  • 感谢您的回答!我刚刚使用了您代码中的一个函数sections.keys.sorted{}
【解决方案2】:

如果我了解您要做什么,您可以先检索您的收藏夹并对其进行排序。

然后你检索那些以#开头的。

之后,您检索其余部分并对其进行排序。

此时您只需将第三组和第二组附加到“收藏夹”数组中。

所以结果将是一个 [Contact],首先是 FAVORITES,然后是以 A、B 等开头的联系人,最后是以 # 开头的联系人

我假设你已经有了联系人,因为我从未使用过 Realm.io,而且你的联系人或表格确实有一个 isFavorite 标志。

伪代码:

func sortContacts(_ aList: [Contact]) -> [Contact]
{
    var retValue = [Contact]()

    var favorites = Set(aList.value(forKeyPath: "isFavorite == true") as![String]).sorted()

    var theRest = Set(aList.value(forKeyPath: "firstLetter") as![String]).sorted()

    retValue.append(favorites)
    retValue.append(theRest)

    return retValue
}

您应该在 viewWillAppear 中调用它,例如:

func viewWillAppear(animated: Bool)
{
    super.viewWillAppear(animated)
    sections = sortContacts(contacts)

    // code
}

【讨论】:

  • 我用伪代码@DamirShakenov 修改了我的答案
猜你喜欢
  • 1970-01-01
  • 2021-08-04
  • 1970-01-01
  • 1970-01-01
  • 2021-08-26
  • 1970-01-01
  • 1970-01-01
  • 2020-01-10
  • 1970-01-01
相关资源
最近更新 更多