0

I am using SwiftUI to generate this dynamic list in a view (showing portion of the generated list):

  • LAVENDER
  • LEMON
  • LIME
  • LIME
  • MANGO

How can I remove the duplicates from the list (e.g. LIME)?

Here is my code that generates the list view:

struct FlavorGroupList: View {
    @ObservedObject private var viewModel = FlavorsViewModel()
    var body: some View {
        List(viewModel.flavors) { flavorListing in
            VStack(alignment: .leading) {
                Text(flavorListing.flavorGroup)
            }
        }
        .onAppear() {
            self.viewModel.fetchData()
        }
    }
}

Here is my view model code:

class FlavorsViewModel: ObservableObject {
    @Published var flavors = [Flavor]()
    private var db = Firestore.firestore()
    func fetchData() {
        db.collection("flavors").order(by: "flavorGroup").addSnapshotListener { (querySnapshot, error) in
            guard let documents = querySnapshot?.documents else {
                print("No documents")
                return
            }
            self.flavors = documents.compactMap { (queryDocumentSnapshot) -> Flavor? in
                return try? queryDocumentSnapshot.data(as: Flavor.self)
            }
        }
    }
}

Here is my model code:

struct Flavor: Identifiable, Codable {
    @DocumentID var id: String? = UUID().uuidString
    var code: String
    var descriptors: [String]
    var flavorGroup: String
    var keywords: [String]
    var legislation: String
    var name: String
}

I am importing the data from a Firestore database.

Thank you in advance for any help offered.

2 Answers2

0

One simple approach could be, to transform your array flavors to a Set first and then converting it back to an Array.

class FlavorsViewModel: ObservableObject {
    @Published var flavors = [Flavor]()
    private var db = Firestore.firestore()
    func fetchData() {
        db.collection("flavors").order(by: "flavorGroup").addSnapshotListener { (querySnapshot, error) in
            guard let documents = querySnapshot?.documents else {
                print("No documents")
                return
            }
            self.flavors = documents.compactMap { (queryDocumentSnapshot) -> Flavor? in
                return try? queryDocumentSnapshot.data(as: Flavor.self)
            }
            self.flavors = Array(Set(flavors))//<- This line

        }
    }
}

See the documentation for reference: https://developer.apple.com/documentation/swift/set

finebel
  • 2,227
  • 1
  • 9
  • 20
  • 1
    The one potential drawback of this is that you'll lose the order of the elements when converting to Set. Use NSOrderedSet instead if the order matters to you: `Array(NSOrderedSet(array: flavors))` – WongWray Jun 30 '21 at 14:31
  • I am going to try this approach and will comment soon with the results. – Mark Burgun Jun 30 '21 at 17:42
  • I replaced my view model class with this class. The duplicates still appear in my list. Is additional code required here to remove the duplicates? – Mark Burgun Jun 30 '21 at 18:32
  • Without further information we can only guess what's wrong with your code. So have you tried to simplify your problem (e.g. remove the firebase functionality and see, whether the problem still occurs)? – finebel Jul 01 '21 at 18:35
0

You can create an empty array of Flavor named unique, loop through the retrieved flavors and add them to the unique array if it doesn't exist using contains(where: _)

func removeDuplicates() -> [Flavor] {
    var unique = [Flavor]()
    self.flavors.forEach { flavor in
        if !unique.contains(where: {$0.name == flavor.name}) {
            unique.append(flavor)
        }
    }
    return unique
}

Visal Rajapakse
  • 1,718
  • 1
  • 9
  • 15
  • I am going to try this approach and will comment soon with the results. – Mark Burgun Jun 30 '21 at 17:08
  • This works, but Array.contains has `O(n)` performance. The performance of the whole process will be `O(n²)`, which is really bad for anything other than very small arrays. Using an `NSOrderedSet`, or an array for the output plus a temporary `Set` for uniqueness will give you `O(n)` performance. – Duncan C Jun 30 '21 at 17:27
  • I added the removeDuplicates function but I do not know how/where to call the function in my code. – Mark Burgun Jun 30 '21 at 17:41
  • You can add it right after the `self.flavors = documents.compactMap {...}` closure – Visal Rajapakse Jun 30 '21 at 19:33