3

I have a .plist file with root dictionary and loading keys of letters as:

["A": ["AXB", "ACD", "ABC"], ... ]

It would be right by:

["A": ["ABC", "ACD", "AXB"], ... ]

Then, I wanna sort this array's itens of the A index. So, I tried do thus:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

var musicalGroups : NSDictionary = NSDictionary()
var keysOfMusicalGroups : NSMutableArray = NSMutableArray()

override func viewDidLoad() {
    super.viewDidLoad()

    let bundle = Bundle.main
    let path = bundle.path(forResource: "bandas", ofType: "plist")
    musicalGroups = NSDictionary(contentsOfFile: path!)!
    keysOfMusicalGroups = NSMutableArray(array: musicalGroups.allKeys)
    keysOfMusicalGroups.sort(using: NSSelectorFromString("compare:"))

}

And I got just the keys of Dictionary sorted using keysOfMusicalGroups.sort code

enter image description here

Any help will be appreciated. Thanks in advance!

5
  • 2
    Your code only sorts the keys. You need to sort each individual array in the main dictionary. Commented Sep 15, 2016 at 3:13
  • Why are you using NSArray, NSDictionary, etc., instead of their Swift counterparts? Commented Sep 15, 2016 at 3:15
  • @NRitH Yes, it is like I have learned to work with tableview indexed. I have implemented those methods . Commented Sep 15, 2016 at 3:21
  • @rmaddy ... yes, but how can I do it? Commented Sep 15, 2016 at 3:23
  • I am posting the repo link here. github.com/gasparteixeira/TableViewIndexed Commented Sep 15, 2016 at 3:26

2 Answers 2

5

You just have to sort your dictionary keys and append each value (array) sorted to the resulting array 2D:

let dict = ["A": ["Angra", "Aerosmith", "ACDC", "Avantasia"],"B": ["Barao Vermelho", "Bon Jovi", "Bee Gees"],"C": ["Cachorro Loco", "Coldplay", "Creed"] ]

let sortedArray2D = dict.sorted{ $0.key < $1.key }.map { $0.value.sorted() }

print(sortedArray2D)  // "[["ACDC", "Aerosmith", "Angra", "Avantasia"], ["Barao Vermelho", "Bee Gees", "Bon Jovi"], ["Cachorro Loco", "Coldplay", "Creed"]]\n"

Your final table view should look like this:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var musicalGroups: [[String]] = []
    var musicalTitles: [String] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        let dict = NSDictionary(contentsOfFile: Bundle.main.path(forResource: "bandas", ofType: "plist")!) as? [String: [String]] ?? [:]
        musicalTitles = dict.keys.sorted()
        musicalGroups = dict.sorted{ $0.key < $1.key }.map { $0.value.sorted() }
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return musicalGroups[section].count
    }
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return musicalTitles[section]
    }
    func numberOfSections(in tableView: UITableView) -> Int {
        return musicalTitles.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: "exemplo")
        cell.textLabel?.text = musicalGroups[indexPath.section][indexPath.row]
        return cell
    }
}
Sign up to request clarification or add additional context in comments.

Comments

-1

A more performance-wise answer, based on @Leo-Dabus's, is:

let dict = ["A": ["Angra", "Aerosmith", "ACDC", "Avantasia"],"B": ["Barao Vermelho", "Bon Jovi", "Bee Gees"],"C": ["Cachorro Loco", "Coldplay", "Creed"] ]

let sortedArray2D: [[String]] = dict.keys.sorted().map{ dict[$0]!.sorted() }

print(sortedArray2D)  // "[["ACDC", "Aerosmith", "Angra", "Avantasia"], ["Barao Vermelho", "Bee Gees", "Bon Jovi"], ["Cachorro Loco", "Coldplay", "Creed"]]\n"

This performs better because the compiler now knows that sortedArray2D has the same size as dict.

Also, this way sortedArray2D is a constant (let), and not a var anymore (allowing even further performance enhancements).

11 Comments

How does the compiler know that map returns a same size array? Is it documented somewhere that the swift compiler has special optimizations around map?
From developer.apple.com/library/content/documentation/Swift/… . In short: The map method takes a closure as its only argument. The closure is called once for each item in the array, and returns an alternative mapped value (possibly of some other type) for that item. In conclusion: by using map, we give the compiler more information of what the new array is going to be. Allowing it to allocate the right memory size (and probably something else that I'm not aware of).
The problem is that map internally likely uses a var and calls to append to create the new array, so while it might seem like an optimization, it's really just the same procedure wrapped in a function, except with the overhead of a method call and repeated closure invocations. So one could argue that it's actually less performant.
If we don't tell the compiler what the size of the new array is going to be, the program will need to allocate new memory from time to time (when we call append). By using map, the compiler knows what the new array size is going to be, removing the memory allocation overhead.
@PatrickGoley, go ahead, try it yourself: swiftlang.ng.bluemix.net/#/repl/57da4349f623dd089776d5c3 , in my tests, map is at least 2 times faster than the for/append alternative.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.