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 !

3

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

2 Comments

This methods has a huge overhead, it runs in O(n^2) complexity, never use this one, use Set instead
Agree with @VitaliiShvetsov. The disadvantage of using Set is it won't keep the sequence, above method does.
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

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.