[Tutor] Indexing a list with nested tuples

Peter Otten __peter__ at web.de
Wed Aug 3 09:12:54 CEST 2011


Alexander Quest wrote:

> Hi guys- I'm having a problem with a list that has nested tuples:
> 
> attributes = [("strength", 0), ("health  ", 0), ("wisdom  ", 0),
> ("dexterity", 0)]
> 
> I've defined the list above with 4 items, each starting with a value of 0.
> The player
> enters how many points he or she wants to add to a given item. The
> selection menu
> is 1 - strength; 2 - health; 3 - wisdom; 4- dexterity. So the "selection"
> variable is actually
> 1 more than the index location of the intended item. So I have the
> following code:
> 
> print("Added ", points, "to ", attributes[selection-1][0], "attribute.")
> 
> My intent with this is to say that I've added this many points (however
> many) to the
> corresponding item in the list. So if the player selects "1", then
> selection = 1, but I subtract
> 1 from that (selection -1) to get the index value of that item in the list
> (in this case 0). Then I
> have [0] to indicate that I want to go to the second value within that
> first item, which is the
> point value. I get an error saying that list indices must be integers, not
> strings. I get a similar
> error even if I just put attributes[selection][0] without the minus 1.
> 
> Also, it seems that the tuple within the list cannot be modified directly,
> so I can't add points to the original value of "0" that all 4 items start
> with. Is there a way to keep this nested list with
> tuples but be able to modify the point count for each item, or will it be
> better to create a dictionary or 2 separate lists (1 for the names
> "Strength, Health, Wisdom, Dexterity" and one
> for their starting values "0,0,0,0")? Any suggestions/help will be greatly
> appreciated!!!

[I'm assuming you are using Python 3. If not replace input() with 
raw_input()]

Let's investigate what happens when you enter an attribute index:

>>> attribute_index = input("Choose attribute ")
Choose attribute 2
>>> attribute_index
'2'

Do you note the '...' around the number?

>>> attribute_index -= 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -=: 'str' and 'int'

It's actually a string, not an integer; therefore you have to convert it to 
an integer before you can do any math with it:

>>> attribute_index = int(attribute_index)
>>> attribute_index
2
>>> attribute_index -= 1
>>> attribute_index
1

Now let's try to change the second tuple:

>>> attributes = [
... ("strength", 0), ("health", 0), ("wisdom", 0), ("dexterity", 0)]
>>> attributes[attribute_index]
('health', 0)
>>> attributes[attribute_index][1] += 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

The error message is pretty clear, you cannot replace items of a tuple.
You can either to switch to nested lists

[["strength", 0], ["health", 0], ...]

or replace the entire tuple with a new one:

>>> name, value = attributes[attribute_index]
>>> attributes[attribute_index] = name, value + 42
>>> attributes
[('strength', 0), ('health', 42), ('wisdom', 0), ('dexterity', 0)]

However, I think the pythonic way is to use a dictionary. If you want the 
user to input numbers you need a second dictionary to translate the numbers 
into attribute names:

>>> attributes = dict(attributes)
>>> lookup = {1: "strength", 2: "health", 3: "wisdom", 4: "dexterity"}
>>> while True:
...     index = input("index ")
...     if not index: break
...     amount = int(input("amount "))
...     name = lookup[int(index)]
...     attributes[name] += amount
...
index 1
amount 10
index 2
amount 20
index 3
amount 10
index 2
amount -100
index
>>> attributes
{'dexterity': 0, 'strength': 10, 'health': -38, 'wisdom': 10}

Personally I would ask for attribute names directly.



More information about the Tutor mailing list