Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comprehensions with multiple input sets

I'm experimenting with python and am stuck trying to understand the error messages in the context of what I am doing.

I'm playing around with comprehensions and trying to find a pattern to create a list/dictionary comprehension with more than one input set (assuming this is possible):

Note: Here the word input set means the input area of the comprehension. In setbuilder notation, from where python derived its comprehensions [Y for X in LIST], Y is the output function, X is the variable and LIST is the input set.

Assume I have the following working code:

from random import randint

mydict = {k: 0 for k in range(10)}
result = {randint(0,9): v + 1 for v in mydict.values()}

I'm not trying to do anything special about it. This is not even useful code because it won't work as expected. All elements in the dictionary will have the value 1, instead of just those pointed at by the random generator. My only objective is to have a basis from where I start my attempt at working with a tuple of input sets.

from random import randint

mydict = {k: 0 for k in range(10)}
result = {k: v + 1 for k, v in (randint(0,9), mydict.values())}

This option gives me: TypeError: 'int' object is not iterable.

By swapping the input sets and unpacking I have:

result = {k: v + 1 for *v, k in (mydict.values(), randint(0,9))}

But this option gives me: TypeError: can only concatenate list (not "int") to list

Are these errors appearing because I am trying to do something the language grammar does not understand, or am I missing something and I could in fact fix the code?

like image 516
Alexandre Bell Avatar asked Apr 20 '15 03:04

Alexandre Bell


1 Answers

You will have to create a separate comprehension for the random numbers, as it currently stands, you have only one random number. Also, you will then need to zip the results to get a combined entity:

>>> from random import randint
>>> mydict = {k: 0 for k in range(10)}
>>> result = {k: v + 1 for k, v in zip([randint(0,9) for _ in range(10)] , mydict.values())}
>>> result
{2: 1, 3: 1, 4: 1, 5: 1, 8: 1, 9: 1}

Note that since your initial dict has the value 0 for all its keys, all the values in the result dict are 1 (0+1).

Also, since we are making the keys random, there can be possible overlaps (say 2 was generated twice), so that's why we don't see all the keys in the result dictionary.

As @wim notes in comments below, a better way to generate this result dictionary would be to use:

>>> {randint(0,9): v+1 for v in mydict.values()}
{0: 1, 1: 1, 2: 1, 3: 1, 6: 1, 7: 1}
like image 145
Anshul Goyal Avatar answered Nov 04 '22 10:11

Anshul Goyal