1

I am trying to write a program which updates values in a dictionary.

stuff = {'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12}
dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby']

#stuff = addToInventory(stuff, dragonLoot)
for i in range(len(dragonLoot)):
        for k, v in stuff.items():
            if dragonLoot[i] == k:
                v += 1

displayInventory(stuff)

As you can see I already moved the snippet in my main to ensure that it's not a problem with the function. The outer for-loop also works. The problem is, v just dosen't get updated. displayInventory() prints the same values as in the declaration at the top.

Thank you in advance for your input!

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
Esoterik
  • 15
  • 5
  • See [this answer](http://stackoverflow.com/a/28757945/1084416) to [this question](http://stackoverflow.com/questions/1135335/increment-int-object) – Peter Wood Sep 16 '15 at 07:11

7 Answers7

1

v does get updated, the problem is that you don't assign it back to stuff[k], so the new value gets lost.

Fix it with

for i in range(len(dragonLoot)):
    for k, v in stuff.items():
        if dragonLoot[i] == k:
            stuff[k] = v + 1
Tim
  • 41,901
  • 18
  • 127
  • 145
1

v does get updated, but stuff[k] does not - they are the same value (originally), but not the same variable. You need to assign the new value to stuff[k], not to v.

Tim
  • 41,901
  • 18
  • 127
  • 145
Amadan
  • 191,408
  • 23
  • 240
  • 301
1

You can use the following approach:

stuff = {'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12}
dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby']

for item in dragonLoot:     
    stuff[item] = stuff.get(item, 0) + 1

print stuff

Giving you:

{'gold coin': 45, 'dagger': 2, 'torch': 6, 'rope': 1, 'arrow': 12, 'ruby': 1}

stuff.get(item, 0) returns item from the dictionary, but if it is not present (such as ruby) it returns the default value of 0. I than add one to the value and assign it back to the dictionary.

Martin Evans
  • 45,791
  • 17
  • 81
  • 97
1

The += operator in Python is tricky. For some types it will modify the object referenced on the left in place. In other cases however, that's not possible (because the type is immutable). In those cases it rebinds the left side to a new object. This won't change other references to the old value that might exist elsewhere.

You can learn about this in a simpler scenario:

x = 1
y = x    # reference to the same int object
y += 1   # can't modify 1 in place, so only rebinds
print(x) # prints 1 still

In your code, x is stuff[k] (accessed implicitly through the loop) and y is v. You need to write stuff[k] = v+1 to make your code do what you want.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
0

stuff.items() returns a tuple, made of k and v.

Both k and v are new and distinct names. Tuples and integers are immutable, so when you do v += 1, python creates a new object with the value updated. The original stuff dictionary remains unaltered.

Use

stuff[k] = v+1

instead

Pynchia
  • 10,996
  • 5
  • 34
  • 43
  • This is not correct. At the start of the body of the loop `v` is not a new object, it's a reference to the same `int` as `stuff[k]`. It's only after the `+=` statement that it gets rebound to a new value (because the `int` is immutable and can't be modified in place). – Blckknght Sep 16 '15 at 07:00
0

An integer is a primitive, not a reference. So, when i=0 and k='gold coin', v is not pointing to 1, v is 1. And then you add 1 to it and it becomes 2, but stuff doesn't change at all.

You need to explicitly change stuff by writing

stuff[k] += 1

rather than adding one to v.

Yannick
  • 139
  • 1
  • 7
  • 1
    None of your first two sentences is true in Python. Python's integers are objects, and are passed by reference just like all other objects. However, they are immutable, which means that the `+=` returns a new object rather than a reference to the same object (which has been modified in place). – Blckknght Sep 16 '15 at 07:02
  • Aargh, I am confusing python with java :-/ – Yannick Sep 16 '15 at 18:43
0

If you want to count items carried by your adventurers, you'd better off using a Counter. They auto-start at 0 and let you simplify the logic:

from collections import Counter

stuff = Counter({'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12})
dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby']

for loot in dragonLoot:
    stuff[loot] += 1
301_Moved_Permanently
  • 4,007
  • 14
  • 28