5

I'm quite new to Swift and I just encountered an error I don't find a solution for. I'm currently working on a game (Boggle, for the curious) and I want to update the list of words that the algorithm has found.

I created a struct to hold each word and the points it scores :

struct ScoredWord: Comparable, Identifiable{
let word: String
var points: Int = 0
let id: UUID

init(word: String){
    self.id = UUID()
    self.word = word
    self.points = self.defineScore(word: word)
}

static func < (lhs: ScoredWord, rhs: ScoredWord) -> Bool {}

static func == (lhs: ScoredWord, rhs: ScoredWord) -> Bool {}

func hash(into hasher: inout Hasher) {

private func defineScore(word: String) -> Int{}

(I removed the content of the func for it's useless to you)

Once the algorithm is done, I have simple loop that created a struct for each word found and stores it in the array that is @Published for display

let foundWords = solver.findValidWords()
    
for found in foundWords {
    wordList.append(ScoredWord(word: found))
}

The array is used in my view this way:

 List(wordListViewModel.wordList, id: \.self) { // 1 Word list
     Text( $0.word )
     Spacer()
     Text("\( $0.points )")
 }

The error I get when I run all of this is:

Fatal error: Duplicate keys of type 'ScoredWord' were found in a Dictionary. 
This usually means either that the type violates Hashable's requirements, or
that members of such a dictionary were mutated after insertion.

I found this post about the same error where a comment states that the error would come from the list not being displayed fast enough and id getting mixed up, but nothing about how to fix it...

Any idea?

CloudBalancing
  • 1,461
  • 2
  • 11
  • 22
ano0ther
  • 73
  • 1
  • 5

2 Answers2

8

I think you are missing a full conformance to the Hashable Protocol

Pay attention to the func hash(into hasher: inout Hasher) function which you are missing

CloudBalancing
  • 1,461
  • 2
  • 11
  • 22
  • Hi @CloudBalancing, thanks for the reply, I indeed missed this func in my struct. Adding it didn't fix my issue though :( – ano0ther Dec 27 '20 at 15:02
  • 1
    Please share the implementation of the function, it probably means that your implementation produce the same Hasher for two different struct instances – CloudBalancing Dec 27 '20 at 15:26
  • Here is what I did: ```func hash(into hasher: inout Hasher) { hasher.combine(id) hasher.combine(word) hasher.combine(points) }``` – ano0ther Dec 27 '20 at 15:36
  • 2
    Did you update your `==` function, i.e equatable function to take the UUID into account as well? – CloudBalancing Dec 27 '20 at 15:55
  • Ok, I'm really ashamed of myself. I should have added the funcs content after all, you would have spotted this mistake earlier... Thanks a lot @CloudBalancing, it fixed my issue ! – ano0ther Dec 27 '20 at 16:00
  • Cool ,happy it helped. BTW - if you. are using UUID - you can remove the dependancy on the word and points variables, as their value will not affect the results (that is the idea of using UUID - which suppose to be unique per initialisation...) – CloudBalancing Dec 27 '20 at 16:01
0

Hash table is a dictionary. What is the true difference between a dictionary and a hash table?

It appears that some structs in your array are made using identical words & points. Add another variable to your struct:

var identifier = UUID()

It will generate a unique ID.

cora
  • 1,916
  • 1
  • 10
  • 18
  • Thanks for the post! I had the same thoughts and tried to add an ID to each struct in the past, but it ended up the same way... I just tried again with the UUID, but I still get my error – ano0ther Dec 27 '20 at 15:23
  • If it’s not this, then you should look into the error message’s second part that mentions wrong conformance to the protocol or mutation of properties – cora Dec 27 '20 at 15:32
  • Just for the hell of it, change those vars to lets – cora Dec 27 '20 at 15:34
  • Yes, that's what CloudBalancing is suggesting in his answer – ano0ther Dec 27 '20 at 15:37
  • @ano0ther Just make sure that the same struct is not being used multiple times. – cora Dec 27 '20 at 15:58
  • That wasn't the case, but I forgot to update the == func with the UUID, so there was a bad matching happening. Thanks for the help! – ano0ther Dec 27 '20 at 16:05