How to quick update all members in Set with out mapping

Hello. I need frequently update members in stored Set in rendering code. The map creates an array and then I need to again create Set from that array. What is most quick way to update all members in Set? I tried next code, but it leads doubling sets count.

struct Bee: Hashable {
    let number = "\(Int.random(in: 0...100))"
    var honeyCount: Int = 0
    mutating func getHoney() { honeyCount += 1 }
}

func run() {
    
    let one = Bee()
    let two = Bee()
    let three = Bee()
    let four = Bee()
    
    var swarm = Set([one, two, three, four])
    // 4
    print(swarm.count)
    
    print("-")
    
    // Cannot assign value of type '[Sets.Bee]' to type 'Set<Sets.Bee>'
    swarm = swarm.map { (bee) -> Bee in
        var bee = bee
        bee.getHoney()
        return bee
    }
    
    // Doubling sets count
    swarm.forEach { bee in
        var bee = bee
        bee.getHoney()
        swarm.update(with: bee)
    }
    
    // 8 (?)
    print(swarm.count)
    
}

Sounds like Bee has some sense of identity (you want to update this particular Bee). In that case, you'd be better off making it a class. Otherwise, the old Bee and the new Bee will be treated as separated subjects, as per value semantic, and you need to remove old data, and reinsert new data. At which point, you're probably better off recreating an entirely new set:

swarm = Set(swarm.map { ... })

Thanks. Looks like it works

    swarm.forEach { bee in
        swarm.remove(bee)
        var bee = bee
        bee.getHoney()
        swarm.insert(bee)
    }

Another thing you could do, is to override the default Equatable implementation, so that the new and old Bees are treated as the same object, I don't think it exactly matches what you're trying to achieve, but it can be done.

Another suggestion would be to try to use Dictionary if it makes sense in your scenario since it has mapValue.

Can’t you just use a for loop over its .indices and do bees[i].getHoney()?

Set conforms to Collection doesn’t it?

    for index in swarm.indices {
        // Cannot use mutating member on immutable value: subscript is get-only
        swarm[index].getHoney()
    }

Looks like subscript on Set has only getter

1 Like

In-place mutation doesn't make much sense anyway. You can easily change the hash value, and so the set needs to move the item, not dissimilar to removing, then reinserting it. Collection is not enough, you'd need at least MutableCollection.

3 Likes

+1 to @Lantua’s suggestions:

  • set of objects
  • map from number to honeyCount
  • maybe even map from number to object/struct with number and honeyCount

But custom Equatable implementation that ignores some of the properties, IMO is an anti-pattern. Eventually you may need to compare full state of the Bee, and things will get confusing.

To avoid this confusion keep types for Bee’s identity and state separated.