skip to Main Content

I have a question about Swift.

I am making a quiz app to learn English words and I want to display the words in the Word class once the player gets right like the picture attached below. However, as you can see, the list has many duplicated values. How can I fix that? Thank you in advance.List View


@Query var playerInfos: [PlayerInfo1]

List {
      ForEach(Array(Set(playerInfos)), id: .self) { playerInfo in
             ForEach(Array(Set(playerInfo.correctWords)), id: .self) { index in
                        Text("(displayeWord[index].word)")
                            .foregroundColor(.black)
                    }
                }
            }
-----------------
@Model
class PlayerInfo1 {
    var playerScore : Int
    var correctWords : [Int] // store the index of the words that the player gets right 
    
    init(playerScore: Int, correctWords: [Int]) {
        self.playerScore = playerScore
        self.correctWords = correctWords
    }
}
-----------------
class Word : Identifiable {
 
}

let displayeWord : [Word] = [
    Word(word: "Arvo", meaning1: "午後", meaning2: "午前"),
    Word(word: "Bin", meaning1: "ゴミ箱", meaning2: "壺"),
    Word(word: "Runners", meaning1: "スニーカー", meaning2: "走る人"),

2

Answers


  1. Try this:

    struct Word : Hashable {
          var id: String {
            return self.word
          }
          let word: String
          let meaning1: String
          let meaning2: String
        }
        
        let displayedWord : [Word] = [
            Word(word: "Arvo", meaning1: "午後", meaning2: "午前"),
            Word(word: "Bin", meaning1: "ゴミ箱", meaning2: "壺"),
            Word(word: "Runners", meaning1: "スニーカー", meaning2: "走る人"),
            Word(word: "Arvo", meaning1: "午後", meaning2: "午前"),
            Word(word: "Bin", meaning1: "ゴミ箱", meaning2: "壺"),
            Word(word: "Runners", meaning1: "スニーカー", meaning2: "走る人"),
        ]
        
        let unique = Array(Set(displayedWord))
    
    Login or Signup to reply.
  2. You could try a different approach, using a function (or a computed property if you wish) to calculate
    the set of unique words to display, instead of multiple ForEach loops in the body of the view.

    Example code:

    struct ContentView: View {
        // @Query var playerInfos: [PlayerInfo1]
        
        // simulated @Query, for testing
        let playerInfos: [PlayerInfo1] = [
            PlayerInfo1(playerScore: 1, correctWords: [1]),
            PlayerInfo1(playerScore: 2, correctWords: [2]),
            PlayerInfo1(playerScore: 3, correctWords: [3]),
            PlayerInfo1(playerScore: 4, correctWords: [4])
        ]
        
        let displayedWord: [Word] = [
            Word(word: "Arvo", meaning1: "午後", meaning2: "午前"),
            Word(word: "Bin", meaning1: "ゴミ箱", meaning2: "壺"),
            Word(word: "Runners", meaning1: "スニーカー", meaning2: "走る人"),
            Word(word: "Arvo", meaning1: "午後", meaning2: "午前"),
            Word(word: "Bin", meaning1: "ゴミ箱", meaning2: "壺"),
            Word(word: "Runners", meaning1: "スニーカー", meaning2: "走る人")]
        
        var body: some View {
            List(uniqueWords()) { unique in
                Text("(unique.word)")
            }
        }
        
        func uniqueWords() -> [Word] {
            var uniqueWords: [Word] = []
            Array(Set(playerInfos)).forEach { playerInfo in
                Array(Set(playerInfo.correctWords)).forEach { index in
                    if index < displayedWord.count {
                        if !uniqueWords.contains(where: {$0 == displayedWord[index]}) {
                            uniqueWords.append(displayedWord[index])
                        }
                    }
                }
            }
            return uniqueWords
        }
    }
    
    struct Word: Identifiable, Equatable {
        let id = UUID()
        var word: String
        var meaning1: String
        var meaning2: String
        
        static func == (lhs: Word, rhs: Word) -> Bool {
            lhs.word == rhs.word && lhs.meaning1 == rhs.meaning1 && lhs.meaning2 == rhs.meaning2
        }
    }
    

    If you prefer using a class for Word, use:

    class Word: Identifiable, Equatable {
        let id = UUID()
        var word: String
        var meaning1: String
        var meaning2: String
        
        init(word: String, meaning1: String, meaning2: String) {
            self.word = word
            self.meaning1 = meaning1
            self.meaning2 = meaning2
        }
        
        static func == (lhs: Word, rhs: Word) -> Bool {
            lhs.word == rhs.word && lhs.meaning1 == rhs.meaning1 && lhs.meaning2 == rhs.meaning2
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search