List of tuple maps in a dictionary, python

I have a list of tuples retrieved from a table in a database that looks like (key, foreignkey, value). There is a lot of relationship between a key and foreignkeys, and I would like to convert it to an index indexed by a foreign key containing the sum of all the values ​​with this foreign key, that is {foreignkey, sumof (value)}. I wrote something pretty detailed:

myDict = {} for item in myTupleList: if item[1] in myDict: myDict [ item[1] ] += item[2] else: myDict [ item[1] ] = item[2] 

but after looking at this question or these two there should be a more concise way of expressing what I would like to do. And if this is a repetition, I skipped it and will remove the question if you can provide a link.

+4
source share
5 answers

Assuming all your values ​​are int s, you can use defaultdict to make this simpler:

 from collections import defaultdict myDict = defaultdict(int) for item in myTupleList: myDict[item[1]] += item[2] 

defaultdict is like a dictionary, except that if you try to get a key that does not exist, it fills in the value returned by the called - in this case, an int that returns 0 when called without arguments.

UPDATE: thanks @gnibbler to remind me, but tuples can be unpacked in a for loop:

 from collections import defaultdict myDict = defaultdict(int) for _, key, val in myTupleList: myDict[key] += val 

Here the three-position tuple is unpacked into the variables _ , key and val . _ is the generic placeholder name in Python, used to indicate that a value is not very important. Using this, we can avoid the hairy indexing of item[1] and item[2] . We cannot rely on this if the tuples in myTupleList not the same size, but I'm sure they are.

(We also avoid the situation where someone looks at the code and thinks it is broken, because the writer thought the arrays were 1-indexed, which I thought when I first read the code. I was not mitigated by this while I read the question, however, in the above loop it’s obvious that myTupleList is a set of three elements and we just don’t need the first one.)

+8
source
 from collections import defaultdict myDict = defaultdict(int) for _, key, value in myTupleList: myDict[key] += value 
+4
source

Here my (tongue on the cheek) answers:

 myDict = reduce(lambda d, t: (d.__setitem__(t[1], d.get(t[1], 0) + t[2]), d)[1], myTupleList, {}) 

This is ugly and bad, but here's how it works.

The first argument to reduce (because it is not clear there) is lambda d, t: (d.__setitem__(t[1], d.get(t[1], 0) + t[2]), d)[1] . I'll talk about this later, but for now, I'll just call it joe (don't be offended by any of the people named Joe). The reduction function basically works as follows:

  joe(joe(joe({}, myTupleList[0]), myTupleList[1]), myTupleList[2]) 

And this is for a list of three elements. As you can see, it mainly uses its first argument to copy each result into the final answer. In this case, the final answer is the dictionary you wanted.

Now for joe . Here joe as def :

 def joe(myDict, tupleItem): myDict[tupleItem[1]] = myDict.get(tupleItem[1], 0) + tupleItem[2] return myDict 

Unfortunately, in Python lambda , the form = or return not allowed, so you need to find it. I am lacking = by calling the dict __setitem__ function directly. I do without returning by creating a tuple with the return value __setitem__ and a dictionary, and then returning the tuple element containing the dictionary. I will change joe slowly so you can see how I did it.

First remove = :

 def joe(myDict, tupleItem): # Using __setitem__ to avoid using '=' myDict.__setitem__(tupleItem[1], myDict.get(tupleItem[1], 0) + tupleItem[2]) return myDict 

Then, so that the whole expression is evaluated to the value that we want to return:

 def joe(myDict, tupleItem): return (myDict.__setitem__(tupleItem[1], myDict.get(tupleItem[1], 0) + tupleItem[2]), myDict)[1] 

I used this use case to reduce and dict many times in my Python programming. In my opinion, dict can use the reduceto(keyfunc, reduce_func, iterable, default_val=None) member reduceto(keyfunc, reduce_func, iterable, default_val=None) . keyfunc will take the current value from the iteration and return the key. reduce_func will take the existing value in the dictionary and the value from the iterable and return the new value for the dictionary. default_val will be passed to reduce_func if there is no key in the dictionary. The return value must be the dictionary itself, so you can do things like:

 myDict = dict().reduceto(lambda t: t[1], lambda o, t: o + t, myTupleList, 0) 
+4
source

It may not be readable, but it should work:

 fks = dict([ (v[1], True) for v in myTupleList ]).keys() myDict = dict([ (fk, sum([ v[2] for v in myTupleList if v[1] == fk ])) for fk in fks ]) 

The first line finds all the unique foreign keys. The second line builds your dictionary, first creating a list (fk, sum (all values ​​for this fk)) - pairs and turning it into a dictionary.

0
source

Take a look at SQLAlchemy and see if this does all the mapping you need and maybe more

0
source

Source: https://habr.com/ru/post/1300472/


All Articles