1

I'v created a struct and I want to populate it with my data.

My struct:

struct CrimeNameSection {

var firstChar: Character
var name: [String]
var detail: [String]
var time: [String]


init(firstLetter: Character, object1: [String], object2: [String], object3: [String]) {

    firstChar = firstLetter // First letter of 'name'
    name = object1
    detail = object2
    time = object3
}

The first value of my struct ('firstChar') should hold the first letter in 'name' to create an alphabetic sections in tableView, the rest ('name','detail','time') should hold the data from my database (three columns: name, detail, time).

My code:

var marrCrimesData : NSMutableArray! // Hold the database

func getSectionsFromData() -> [CrimeNameSection] {
    guard marrCrimesData != nil else {
        return []
    }


    var sectionDictionary =  [CrimeNameSection]()
    for crime in marrCrimesData {
        let crime = crime as! CrimesInfo
        let firstChar = CrimeNameSection(firstLetter: crime.name[crime.name.startIndex], object1: [crime.name], object2: [crime.detail], object3: [crime.time])
        if var names = firstChar {
            names.append(crime.name)
            sectionDictionary[firstChar] = names
        } else {
            sectionDictionary[firstChar] = [crime.name]
        }
    }

    let sections = sectionDictionary.map { (key, value) in
        return CrimeNameSection(firstLetter: key, name: value)
    }
    let sortedSections = sections.sorted { $0.firstLetter < $1.firstLetter }

    return sortedSections 
}

I get errors all over the place, I need help with storing the data inside my struct and sort it alphabetically. Thank you all

1
  • what kind of error do you have? Commented Nov 12, 2016 at 16:46

2 Answers 2

1

Consider

struct Crime {
    let name: String
    let detail: String
    let time: String
}

let crimes = [
    Crime(name: "Foo", detail: "detail 1", time: "9am"),
    Crime(name: "Bar", detail: "detail 2", time: "10am"),
    Crime(name: "Baz", detail: "detail 3", time: "11am"),
    Crime(name: "Qux", detail: "detail 4", time: "12am")
]

One approach is to just build an dictionary indexed by the first character and then sort it:

var crimeIndex = [Character: [Crime]]()
for crime in crimes {
    if let firstCharacter = crime.name.characters.first {
        if crimeIndex[firstCharacter] == nil {
            crimeIndex[firstCharacter] = [crime]
        } else {
            crimeIndex[firstCharacter]?.append(crime)
        }
    }
}

let sortedIndex = crimeIndex.sorted { $0.0 < $1.0 }

The advantage of the above is that we can use the dictionary to efficiently find the section. If you really want to use your custom "name section" structure, I'd first make it to use an array of Crime objects (having disjointed arrays of the properties of a Crime can be fragile, e.g. if you later decide to add sorting of the crimes). So it might look like:

struct CrimeNameSection {
    let firstCharacter: Character
    var crimes: [Crime]
}

And because we've lost some of the Dictionary efficiency for finding the index and have manually iterate through looking for the section, and I'll go ahead and do an insertion sort at the time, saving me from having to do a separate sort later:

var crimeSections = [CrimeNameSection]()
for crime in crimes {
    if let firstCharacter = crime.name.characters.first {
        var hasBeenAdded = false

        for (index, crimeIndex) in crimeSections.enumerated() {
            if firstCharacter == crimeIndex.firstCharacter {  // if we found section, add to it
                crimeSections[index].crimes.append(crime)
                hasBeenAdded = true
                break
            }
            if firstCharacter < crimeIndex.firstCharacter {   // if we've passed where the section should have been, insert new section
                crimeSections.insert(CrimeNameSection(firstCharacter: firstCharacter, crimes: [crime]), at: index)
                hasBeenAdded = true
                break
            }
        }

        // if we've gotten to the end and still haven't found section, add new section to end

        if !hasBeenAdded {
            crimeSections.append(CrimeNameSection(firstCharacter: firstCharacter, crimes: [crime]))
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

First of all you could not instantiate an Array and map over it like a dictionary

var sectionDictionary = [CrimeNameSection]() // Here you are init an Array

For a dictionary you have also to specify the key, for instance if the key is a string:

var sectionDictionary = [String: CrimeNameSection]() // Dictionary init

But be aware that the key have to be unique so that the dict would work properly.
Another problem here is the constructor in your .map function because you have not created a constructor for your CrimeNameSection that only takes two parameters:

init(firstLetter: Character, object1: [String], object2: [String], object3: [String]) {

    firstChar = firstLetter // First letter of 'name'
    name = object1
    detail = object2
    time = object3
}

// Another constructor with 2 arguments
 init(firstLetter: Character, object1: [String]) {

    firstChar = firstLetter // First letter of 'name'
    name = object1
    detail = []()
    time = []()
}

If you don't want to use another constructor then you have to provide default values to object2 and object3 in your initial constructor.

Comments

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.