5

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?

Alexandre Bell
  • 3,141
  • 3
  • 30
  • 43
  • 4
    It's not clear what output you *expect*. Say `randint(0,9)` returned 3; what `result` would you want? – DSM Apr 20 '15 at 03:05
  • Do you want a dict with keys from `range(10)` and random values from `randint`? – Navith Apr 20 '15 at 03:07
  • 1
    You folks are focused on the code intention. The only intention here is to see if there is a way to have a tuple of input sets in a comprehension. The code is just my basis for experimentation. – Alexandre Bell Apr 20 '15 at 03:15
  • —1 until you provide an example output – wim Apr 20 '15 at 03:16
  • @AlexandreBell: we can come up with a half-dozen ways to "have a tuple of input sets in a comprehension" (although since there are no sets at all in your question, and none in the answer you accepted, I'm not sure you know that `set` means something in Python). Most of them will have nothing to do with anything you're interested in, which is why we can't know how to "fix the code" without knowing what it's supposed to be doing in the first place. As a game, we can guess what's most like what you're imagining, of course. – DSM Apr 20 '15 at 03:23
  • @DSM 'input set' is the name given to the input area of the set-builder mathematical notation from which Python derived its comprehensions. [Y for X in LIST], Y is the output function, X the variable and LIST the input set. Also the question was answered very satisfactorily. I think it was obvious at least to someone what was my intention. Thank you for your feedback – Alexandre Bell Apr 20 '15 at 03:29
  • I made an edit to the question hoping this addresses some of your concerns. I'm still trying to understand from the initial question, what was that gave so much confusion, especially when I had a great answer within a few minutes. But here it is. – Alexandre Bell Apr 20 '15 at 03:48
  • Agree with DSM. It's not very clear your intentions, and mu made an educated guess that you were grasping for `zip`. But you could have just as well been looking for `itertools.chain` or something else ... – wim Apr 20 '15 at 04:30
  • example clear and easy to answer question: http://stackoverflow.com/q/29739385/674039 – wim Apr 20 '15 at 04:35

1 Answers1

7

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}
Anshul Goyal
  • 73,278
  • 37
  • 149
  • 186
  • 2
    That's a strange way to go about it. You may as well just put randint(0, 9) in as the k and only include the v in the comprehension. – wim Apr 20 '15 at 03:10
  • 1
    @wim That's right, I was focussed on telling OP whatis wrong with the current code... – Anshul Goyal Apr 20 '15 at 03:12
  • 1
    That is amazing, mu! Thanks for helping me find where I was going wrong. @wim, this is only an experiment. The real intention was to try and find a way to have a tuple of input sets – Alexandre Bell Apr 20 '15 at 03:13