List with subsections and deletable Elements.

Hello everybody.

I have an array of students which the app should divide into 5 groups wich should be shown in different sections of the List.

To do this I have created the List:

List{
                    Section("Group 1") {
                        ForEach(splitArray(schueler)[0], id: \.self) {SchuelerName in Text(SchuelerName)}
                            .onDelete(perform: delete)
                    }
                    
                    Section("Group 2"){
                        (ForEach(splitArray(schueler)[1], id: \.self) {SchuelerName in Text(SchuelerName)}
                            .onDelete(perform: delete))
                    }
                    
                    Section("Group 3"){
                        (ForEach(splitArray(schueler)[2], id: \.self) {SchuelerName in Text(SchuelerName)}
                            .onDelete(perform: delete))
                    }
                    
                    Section("Group 4"){
                        (ForEach(splitArray(schueler)[3], id: \.self) {SchuelerName in Text(SchuelerName)}
                            .onDelete(perform: delete))
                    }
                    
                    Section("Group 5"){
                        (ForEach(splitArray(schueler)[4], id: \.self) {SchuelerName in Text(SchuelerName)}
                            .onDelete(perform: delete))
                    }

And a function that defines my groups by splitting my array:

func splitArray<T>(_ array: [T]) -> [[T]] { let count = array.count let chunkSize = count / 5 var remainder = count % 5 var startIndex = 0 var result: [[T]] = []

for _ in 1...5 {
    let chunkCount = chunkSize + (remainder > 0 ? 1 : 0)
    let endIndex = startIndex + chunkCount
    let chunk = Array(array[startIndex..<endIndex])
    result.append(chunk)
    startIndex = endIndex
    remainder -= 1
}

return result

}

the delete function I have designed a always:

    func delete (indexSet: IndexSet) {
            schueler.remove(atOffsets: indexSet)

my problem is that when I now delete a Student from the second section, he just goes into the first one and another one gets deleted.

Does anyone know why this code be the case and how to fix it? Thanks a lot in advance

Replies

hi,

when the delete function is called, the indices handed to the delete function are relative to the array indices in the section where the .onDelete modifier is attached ... for example, splitArray(schueler)[3] has chunkSize (or possibly fewer) elements with indices in the range 0 ... chunkSize - 1 ; yet your 'delete function removes elements in the main schueler array using those indices directly, without regard to which section triggered the deletion call.

if you can pass the section/group number information along to your delete function, you can first adjust the incoming indices by section. for example, in the third group with a chunkSize of 7, adjust the incoming indices 0 ... 6 to instead be 14 ... 20, and then delete from the main schueler array using the adjusted indices.

first, make a simple syntax modification to the .onDelete invocations in each section, so that your delete function will also receive section/group information. for example, in the third section:

Section("Group 3") {
  ForEach(splitArray(schueler)[2], id: \.self) {
    SchuelerName in Text(SchuelerName)
  }
    .onDelete { indexSet in delete(indexSet: indexSet, inGroup: 3) }
}

update your delete function's signature to handle a second parameter, and begin by adjusting the incoming indices accordingly to determine matching indices in the main schueler array. then do the appropriate deletions.

func  indexSet in delete(indexSet: IndexSet, inGroup group: Int) {
  // this is your code to write ... i would think indices in the indexSet would have to be
  // offset by (group - 1) * chunkSize first before doing any deletions.
}

hope that helps,

DMG

To complement DelawareMathGuy correct answer:

func delete (indexSet: IndexSet, inGroup group: Int) {
    var offset = 0
    if group > 0 {
      for iGroup in 0..< group-1 {
         offset += splitArray(schueler)[iGroup].count  // If I understood correctly how you split
      }
    }
     
   for i in indexSet {
       schueler.remove(atOffsets: [i+offset])
   }
}

If you have several indexes in indexSet, you should start removing the highest index and go in reverse order

   let indexArray = Array(indexSet).ordered(by: >)
   for i in indexArray {
       schueler.remove(atOffsets: [i+offset])
   }

Note that when you delete, chinkSizes may change…

For a more compact cod, if you have several indexes to delete:

func delete (indexSet: IndexSet, inGroup group: Int) {
    var offset = 0
    if group > 0 {
      for iGroup in 0..< group-1 {
         offset += splitArray(schueler)[iGroup].count 
      }
    }
     
   schueler.remove(atOffsets: indexSet.map { $0 + offset} )
}