0

I have an array of questions and each question have a unique lineID. The problem is when I sync the questions from the server sometimes (1 time at 1000 syncs ) the questions are duplicated. Instead of 28 questions I have 56. I want somehow to filter the array of questions and if there are 2 questions with the same lineID (duplicated) then to append only 1 into my array of objects. Can anyone help me with this issue ?

// Get the questions from CoreData.
  func loadQuestionsUsing(templateId: Int) {
     
    do {
      guard let questions = try Question.getQuestions(templateId: templateId, context: context) else { return }
       
      checklistSections = []
       
      questions.forEach { question in
         
        // If the question lineID is duplicated, then select only one of that 2 duplications.
         
        // code here
         
        print(“Question Line ID: \(question.lineId)“)
         
        // If the question have the same templateID as the Checklist Template which user selected from the menu then create an object with that question properties.
        if question.templateId == templateId {
           
          let showVehicle = question.vehicle == 1
          let showTrailer = question.trailer == 1
          let highlight = question.highlight == 1
          let pg9 = question.pg9 == 1
          let question = ChecklistQuestion( rowID: Int(question.id),
                           templateID: Int(question.templateId),
                           lineID: Int(question.lineId),
                           poolID: Int(question.poolId),
                           descript: question.descript ?? String(),
                           showVehicle: showVehicle,
                           showTrailer: showTrailer,
                           header: question.header ?? String(),
                           highlight: highlight,
                           pg9: pg9,
                           imagesPath: [])
          let header = (question.header.isEmpty) ? Constants.questionsNoHeader : question.header
           
          // check if question.header (Section) exist in the ChecklistItemSection
          if let existingSection = checklistSections.firstIndex(where: { $0.name == header }) {
             
            // If section exist then append the ChecklistItem (question) to that existing section.
            checklistSections[existingSection].questions.append(question)
          } else {
            // If section don’t exist then create the section (question.header) and also append the question to that section.
            checklistSections.append(ChecklistSection(name: header, questions: [question]))
          }
        }
      }

    } catch {
      print(“Error while fetching the Questions from CoreData: \(error.localizedDescription)“)
    }
     
    print(“CHECKLIST CONTAINS: \(checklistSections.count) Sections.“)
  }

Struct for ChecklistSection:

class ChecklistSection {

    var name: String                            // Name of the section
    var questions: [ChecklistQuestion]          // List with all questions from a Section
    
    init(name: String, questions: [ChecklistQuestion]) {

        self.name = name
        self.questions = questions
    }
}

My stupid solution:

func findDuplicatedQuestions(checklistSections: [ChecklistSection]) -> [ChecklistSection] {
        
        var duplicates: [ChecklistQuestion] = []
        
        var prevQuestionLineID: Int = 0
        var addedQuestionLineID: Int = 0
        
        checklistSections.forEach { section in
            section.questions.forEach { question in
                if (prevQuestionLineID == question.lineId && addedQuestionLineID != question.lineId) {
                    duplicates.append(question)
                    addedQuestionLineID = question.lineId
                }
                
                prevQuestionLineID = question.lineId
            }
        }
        
        return checklistSections
    }

Thanks for reading this !

Flo
  • 429
  • 4
  • 13

2 Answers2

1

Conform your ChecklistQuestion to Equatable, implement == so it knows how to compare two instances.

class ChecklistQuestion: Equatable {
static func ==(lhs: ChecklistQuestion, rhs: ChecklistQuestion) -> Bool {
return lhs.lineID == rhs.lineID
}
}

Then using this extension to remove duplicate items:

extension Array where Element: Equatable {
    
    /// Remove Duplicates
    var unique: [Element] {
        // Thanks to https://github.com/sairamkotha for improving the method
        return self.reduce([]){ $0.contains($1) ? $0 : $0 + [$1] }
    }
}

Usage:

var questions: [ChecklistQuestion] = ...
questions.unique
//or 
var uniqueQuestions = questions.unique

Extension credits to https://github.com/dillidon/alerts-and-pickers

Duy Nguyen
  • 226
  • 1
  • 5
0

In case you need preserve order and still use arrays (and run in O(n)). Use this:

func getUnique(questions: [ChecklistQuestion]) -> [ChecklistQuestion] {
   var set = Set<ChecklistQuestion>()
   var res = [ChecklistQuestion]()

   for question in questions {
     if !set.contains(question) {
         res.append(question)
         set.insert(question)
     }
    }

   return res
}

And you need to implement Hashable protocol for your model

Vitalii Shvetsov
  • 404
  • 2
  • 11