1

I have this dictionary:

d = {'a': (1, 2, 'a'), 'b': (1, 2, 'b'), 'c': (2, 4, 'c'), 'd': (1, 3, 'd'), 'e': (0, 1, 'e'), 'f': (0, 1, 'f'), 'g': (1, 3, 'g'), 'h': (0, 1, 'h'), 'j': (1, 2, 'j'), 'i': (0, 1, 'i'), 'k': (-1, 0, 'k')}

How can I subtract the value by 1 for a specific key/value pair in this dictionary if the key matches the parameter?

For example, I want to subtract the values of key a by 1, so that it now displays:

{'a': (0, 1, 'a')

How can I edit the values of that specific key and decrease only the integers by 1 while creating the same dictionary again?

Code so far:

def matching(key_to_subtract): 
    for key, value in d.items():
        if key_to_subtract == key:


matching("a")

Desired Output:

{'a': (0, 1, 'a'), 'b': (1, 2, 'b'), 'c': (2, 4, 'c'), 'd': (1, 3, 'd'), 'e': (0, 1, 'e'), 'f': (0, 1, 'f'), 'g': (1, 3, 'g'), 'h': (0, 1, 'h'), 'j': (1, 2, 'j'), 'i': (0, 1, 'i'), 'k': (-1, 0, 'k')}
  • 1
    Possible duplicate of [Python: changing value in a tuple](https://stackoverflow.com/questions/11458239/python-changing-value-in-a-tuple) – metatoaster Jan 11 '19 at 05:55
  • Also, the assignments to elements in tuple are immutable (though the objects referenced by those assignments may be mutable themselves). – metatoaster Jan 11 '19 at 05:57

5 Answers5

1

Since a tuple is immutable you have to build a new one and bind it to the key. You do not, however, have to iterate a dict to search for a given key. That is the whole point of a dict:

def decrement(d, k): 
    # if k in d:  # if you are not certain the key exists
    d[k] = tuple(v-1 if isinstance(v, int) else v for v in d[k])
user2390182
  • 72,016
  • 6
  • 67
  • 89
0

As tuples are immutable you have to rebuild the tuple again and reassign the new tuple to the same key you got it from. This can be written in 1-2 lines using comprehensions but would make it difficult to understand, hope it helps!

Using generator expressions

def matching(key_to_subtract):
    # generator expression force evaluated as tuple
    d[key_to_subtract] = tuple(item-1 if isinstance(item, int) else item for item in d.get(key_to_subtract)) 

Expanded form

d = {'a': (1, 2, 'a'), 'b': (1, 2, 'b'), 'c': (2, 4, 'c'), 'd': (1, 3, 'd'), 'e': (0, 1, 'e'), 'f': (0, 1, 'f'), 'g': (1, 3, 'g'), 'h': (0, 1, 'h'), 'j': (1, 2, 'j'), 'i': (0, 1, 'i'), 'k': (-1, 0, 'k')}

def matching(key_to_subtract): 

    buffer = [] # to build new tuple later from this list
    for item in d.get(key_to_subtract): # get the tuple and iterate over
        try:
            buffer.append(item - 1) # subtract 1
        except TypeError:
            buffer.append(item) # append directly if its not integer

    d[key_to_subtract] = tuple(buffer) # reassign the list as tuple

matching("a")
Vineeth Sai
  • 3,389
  • 7
  • 23
  • 34
  • 1
    That's not comprehension afaik. There is no tuple-comprehension expression in Python. I believe it is a generator expression – Adrian Shum Jan 11 '19 at 06:25
  • 1
    They are not effectively the same. The second one builds a completely spurious `list` object in memory and the repeated `append` will resize the lists's underlying array possibly multiple times. – user2390182 Jan 11 '19 at 06:34
  • oh, thank you for the insight. I will update my answer:) – Vineeth Sai Jan 11 '19 at 06:36
0

You cannot change the content of a tuple. So you need to construct a new tuple and assign it to the dict:

d = {'a': (1, 2, 'a'), 'b': (1, 2, 'b'), 'c': (2, 4, 'c')}
d['a'] = tuple( i - 1 if isinstance(i, int) else i for i in d['a'] )

# d become {'a': (0, 1, 'a'), 'b': (1, 2, 'b'), 'c': (2, 4, 'c')}
Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
0

From your question, I propose another different approach from your code. The reason is because d.items() create a view which is good for checking but not for updating the code.

Therefore, I suggest using d.keys() to search for instance of key_to_subtract. Then change the tuple to list (or you can you another method of slicing the tuple at the position you want then add the new value in which can be faster in the case of a large tuple) then replacing that key with the new value (after changing it back from list to tuple):

def matching(key_to_subtract):
    #check for key_to_subtract
    #if found
    if key_to_subtract in d.keys():
        #change to list
        lst_val = list(d[key_to_subtract])

        #subtract the two values
        lst_val[0]-=1
        lst_val[1]-=1

        #change back to tuple
        tuple_val = tuple(lst_val)

        #replace the old value of the same key with the new value
        d[key_to_subtract] = tuple_val

based on the functions in: https://docs.python.org/3.7/library/stdtypes.html#dict-views

nhtnhan
  • 105
  • 2
  • 7
-1

you can do in this way as tuple are immutable objects.

d = {'a': (1, 2, 'a'), 'b': (1, 2, 'b'), 'c': (2, 4, 'c'), 'd': (1, 3, 'd'), 'e': (0, 1, 'e'), 'f': (0, 1, 'f'), 'g': (1, 3, 'g'), 'h': (0, 1, 'h'), 'j': (1, 2, 'j'), 'i': (0, 1, 'i'), 'k': (-1, 0, 'k')}

def change_value_by_key_pos(data, key, pos, step):
    for k,v in data.items():
        if k == key:
            list_items = list(data[key])
            list_items[pos] = list_items[pos]+step
            data[key] = tuple(list_items)
    return data
data = change_value_by_key_pos(d,'a',1,1)
print(data)
Laxmikanta Nayak
  • 375
  • 2
  • 10