简体   繁体   English

如何按字母顺序对二维数组中的数据进行排序?

[英]How to sort the data in in a twoDimensional array alphabetically?

I am currently having a big issue sorting my Data alphabetically in a 2D array. 我目前在2D数组中按字母顺序排序我的数据有一个大问题。 I'm going to try to give you every detail to be as clear as possible. 我将尽力为您提供尽可能清晰的细节。

Currently, I am fetching my contacts with the CNContactStore. 目前,我正在通过CNContactStore获取我的联系人。 This all works fine. 一切正常。 I am able to retrieve all the data I want out of my contacts. 我能够从联系人中检索出我想要的所有数据。

Now, I created the following struct: 现在,我创建了以下结构:

struct FavoritableContact {
    let contact: CNContact
    var hasFavorited: Bool
}

With this, I declared and initialized the following array: 有了这个,我声明并初始化了以下数组:

var favoritableContacts = [FavoritableContact]()

Once I retrieved my contacts, I simply appended them to favoritableContacts; 一旦我检索到我的联系人,我只需将它们附加到favitableContacts;

try store.enumerateContacts(with: request, usingBlock: { (contact, stopPointerIfYouWantToStopEnumerating) in

  favoritableContacts.append(FavoritableContact(contact: contact, hasFavorited: false))

})

To sort them in alphabetical order in the same array, I simply did the following: 要在同一个数组中按字母顺序对它们进行排序,我只需执行以下操作:

 var sortedContacts = favoritableContacts.sorted { $0.contact.familyName < $1.contact.familyName }

Now if possible, I want to create the following 2D array, 现在,如果可能的话,我想创建以下2D数组,

var 2D = [
        [FavoritableContact] //"A"
        [FavoritableContact], //"B"
        [FavoritableContact], //"C"
        [FavoritableContact], //"D"
        ...
    ]

I am just not sure how to take my sortedContacts array and separate alphabetically. 我只是不确定如何采用我的sortedContacts数组并按字母顺序分开。

I am very new here, If I forgot something, or I didn't do somethign right please let me know. 我在这里很新,如果我忘记了什么,或者我没有做正确的事,请告诉我。

As was pointed out in the comments, a dictionary with first letters as keys is probably the better way to go as it is much easier to access, though perhaps you have a reason for wanting to use a 2d array instead. 正如评论中指出的那样,首字母作为键的字典可能是更好的方式,因为它更容易访问,但也许你有理由想要使用2d数组。 To achieve that you could do something like this: 要做到这一点,你可以做这样的事情:

//Create an empty array filled with 26 arrays of FavorableContact
var array2d = Array<[FavoritableContact]>(repeating: [FavoritableContact](), count: 26)

//Find the ascii value for "A" to use as your base
let aAscii = Int("A".unicodeScalars.filter({ $0.isASCII }).map({ $0.value })[0])  //This returns 65, btw, so you could also just hardcode

//Go through your original array, find the first letter of each contact, and append to the correct array
favoritableContacts.forEach { (contact) in

    //Get the ascii value for the first letter
    let firstLetter = Int(contact.contact.familyName.prefix(1).uppercased().unicodeScalars.filter({ $0.isASCII }).map({ $0.value })[0])

    //Append to the array for this letter by subtracting the ascii value for "A" from the ascii value for the uppercased version of this letter.
    array2d[firstLetter - aAscii].append(contact)
}

This is not the cleanest thing in the world, and it assumes standard English language alphabet with no diacritics, symbols, numbers or anything else. 这不是世界上最干净的东西,它采用标准英语字母表,没有变音符号,符号,数字或其他任何东西。 Assuming that is true it gets the job done. 假设这是真的,它就完成了工作。

Could use something like this. 可以使用这样的东西。

var contactsLeftToSort : [FavoritableContact] = []
var doubleArray : [[FavoritableContact]?] = [[FavoritableContact]?]()

var index : Int = 0

for char in "ABCDEFGHIJKLMNOPQRSTUV" {
    doubleArray.append(nil)
    var i = 0
    while i < contactsLeftToSort.count {
        let contact = contactsLeftToSort[i]
        if contact.name.first == char {
            doubleArray[index] == nil ? doubleArray[index] = [contact] : doubleArray[index]!.append(contact)
            contactsLeftToSort.remove(at: i)
        }

        //assuming original list is alphabetized.. if not, delete this line.
        if contact.name.first! > char { break }
        i += 1
    }
    index += 1
}

As I wrote in the comments above, I think you can achieve this in a much more elegant way by using a dictionary instead of an array. 正如我在上面的评论中所写,我认为你可以通过使用字典而不是数组以更优雅的方式实现这一点。

SWIFT 4 SWIFT 4

let sortedContacts: [FavoritableContact] = ... // An array of FavoritableContact objects, they should be sorted
let groupedContacts = Dictionary(grouping: contacts, by { $0.familyName.first! })

You now have a dictionary of all your contacts where the keys are the alphabetical letters (ie. AZ) and the values are arrays of sorted FavoritableContact objects (assuming you sorted the big array of FavoritableContacts before creating the dictionary). 您现在拥有所有联系人的字典,其中键是按字母顺序排列的字母(即AZ),值是已排序的FavoritableContact对象的数组(假设您在创建字典之前对大量的FavoritableContacts进行了排序)。

If you wanted to use this as the datasource for your tableview, you would make the number of sections all the possible first letters of family names. 如果您想将此作为tableview的数据源使用,则可以将所有可能的姓氏首字母的部分数量设置为。 For the number of rows in each section, you return the count of the array for the key like so: 对于每个部分中的行数,您将返回该键的数组计数,如下所示:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    let letterForSection = letterForSection() // Custom method to get the section of the letter
    return contactsDict[letterForSection].count
}

The rest of the datasource methods would work in a similar way. 其余的数据源方法将以类似的方式工作。

Man, all of these answers are really over-complicating this. 老兄,所有这些答案真的过于复杂了。 All you need is something along the lines of: 您所需要的只是以下内容:

let groupedContacts = Dictionary(grouping: contacts, by: { $0.contact.firstName.first! })


for initial, contacts in groupedContacts.lazy.sorted().{ $0.key < $1.key} {
    print("#################", initial)
    contacts.forEach{ print($0) }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM