Unwrap and update value in one clause?

I wanted to unwrap an optional value and update it at the same time to be displayed, but I can’t figure out how to do that because the value is already unwrapped, so I find I have to update it in one If Let clause, and then read out the updated value in another:

    if let tallyUpdate = dispatchTally[forProduct.name] {
        let updatedTally = tallyUpdate + 1
        dispatchTally.updateValue(updatedTally, forKey: forProduct.name)
        }
        if let tallyUpdated = dispatchTally[forProduct.name] {
            print("\(forProduct.name) has been updated to (\(forProduct.name) tally: \(tallyUpdated))")
        }

I would have preferred it all in one clause, but it’s a catch22.

Is it possible please?

Since you’ve already unwrapped the value, and set it to updatedTally, you can just reuse updatedTally (Logically updatedTally would have the same value as tallyUpdated When you print it out):

if let tallyUpdate = dispatchTally[forProduct.name] {
    let updatedTally = tallyUpdate + 1
    dispatchTally.updateValue(updatedTally, forKey: forProduct.name)
    print("\(forProduct.name) has been updated to (\(forProduct.name) tally: \(updatedTally))")
}
1 Like

Use optional map and assign to itself:

  1> var tallies:[Int: Int] = [0: 0]
tallies: [Int : Int] = 1 key/value pair {
  [0] = {
    key = 0
    value = 0
  }
}
  2> tallies[0] = tallies[0].map{ $0 + 1 }
  3> tallies
$R0: [Int : Int] = 1 key/value pair {
  [0] = {
    key = 0
    value = 1
  }
}
// increments `tallies[0]`, as it should
  4> tallies[1] = tallies[1].map{ $0 + 1 } 
  5> tallies 
$R1: [Int : Int] = 1 key/value pair {
  [0] = {
    key = 0
    value = 1
  }
}
// does nothing, since `tallies[1]` doesn’t exist
1 Like

I just want to point out that you can update a dictionary value in-place with optional chaining:

dispatchTally[forProduct.name]? += 1
6 Likes

Note, this will silently do nothing if forProduct.name isn't already present, which is a bit of an unpleasant gotcha unfortunately.

Assuming you aren't pre-seeding the dictionary with keys set to zero, you probably want dispatchTally[forProduct.name, default: 0] += 1

(and if you are, you probably want ! :)

3 Likes

That’s a funny way to spell “super awesome feature”. :-)

1 Like

Hello again, thank you for your reply.

That was exactly what I did. But the issue was that the value unwrapped was not updated inside the clause, so it only showed the previous value at the time of unwrapping.

It works fine when I tried in my playground.
It is possible that you use the wrong variable.
There are a few variables in that scope that have similar value after all.

1 Like

Thanks for the conscience piece of code Nevin, I would only need two lines of code to set the values and retrieve it. However, Ben_Coheen is right, I would need to use the “Bang Operator” to get access to the value explicitly, and while only for use in the LLDB, I was taught never to use it. Although Swift will allow be to wrap the value (now an optional, thanks to String Interpolation) with a String: String(describing: productUpdated).

In the end, it turned out that Lantua was right and I had missed one of the constants, as can be seen in my original block of code, where I should have used the past tense when updating the dictionary.

Ms. Swift was a little too complicated for me, but I’m sure one day map will make more sense.

Thank you to everybody for your help.

Learning all the time.