Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   expression form of one-to-many dict? (http://www.velocityreviews.com/forums/t339393-expression-form-of-one-to-many-dict.html)

Steven Bethard 12-17-2004 09:14 PM

expression form of one-to-many dict?
 
So I end up writing code like this a fair bit:

map = {}
for key, value in sequence:
map.setdefault(key, []).append(value)

This code basically constructs a one-to-many mapping -- each value that
a key occurs with is stored in the list for that key.

This code's fine, and seems pretty simple, but thanks to generator
expressions, I'm getting kinda spoiled. ;) I like being able to do
something like the following for one-to-one mappings:

dict(sequence)

or a more likely scenario for me:

dict((get_key(item), get_value(item) for item in sequence)

The point here is that there's a simple sequence or GE that I can throw
to the dict constructor that spits out a dict with my one-to-one mapping.

Is there a similar expression form that would spit out my one-to-many
mapping?

Steve

Tim Peters 12-17-2004 09:32 PM

Re: expression form of one-to-many dict?
 
[Steven Bethard]
> So I end up writing code like this a fair bit:
>
> map = {}
> for key, value in sequence:
> map.setdefault(key, []).append(value)
>
> This code basically constructs a one-to-many mapping -- each
> value that a key occurs with is stored in the list for that key.
>
> This code's fine, and seems pretty simple, but thanks to generator
> expressions, I'm getting kinda spoiled. ;) I like being able to do
> something like the following for one-to-one mappings:
>
> dict(sequence)
>
> or a more likely scenario for me:
>
> dict((get_key(item), get_value(item) for item in sequence)
>
> The point here is that there's a simple sequence or GE that I can
> throw to the dict constructor that spits out a dict with my one-to-
> one mapping.


It's a simple sequence because it's a simple task. It's even simpler
than perhaps it "should be", since it arbitrarily decides that, if
more than one instance of some key is seen, it will only remember the
value associated with the last instance of that key.

> Is there a similar expression form that would spit out my one-to-
> manymapping?


There's a straightforward one-liner in 2.4 (but not notably concise),
if your keys are totally ordered:

from itertools import groupby
d = dict((k, map(get_value, g))
for k, g in groupby(sorted(sequence, key=get_key),
key=get_key))

The real purpose of that is to increase your appreciation for your
original spelling <0.2 wink>.

Steven Bethard 12-17-2004 10:09 PM

Re: expression form of one-to-many dict?
 
Tim Peters wrote:
>>The point here is that there's a simple sequence or GE that I can
>>throw to the dict constructor that spits out a dict with my one-to-
>>one mapping.

>
>
> It's a simple sequence because it's a simple task. It's even simpler
> than perhaps it "should be", since it arbitrarily decides that, if
> more than one instance of some key is seen, it will only remember the
> value associated with the last instance of that key.


Good point. That's sort of an arbitrary behavior decision, which, while
reasonable in most situations is not desirable in mine. In thinking
about this, it struck me that one solution is to change that behavior:

>>> class OneToMany(object, UserDict.DictMixin):

.... def __init__(*args, **kwds):
.... self, args = args[0], args[1:]
.... self._dict = {}
.... self.update(*args, **kwds)
.... def __getitem__(self, key):
.... if not key in self._dict:
.... self._dict[key] = []
.... return self._dict[key]
.... def __setitem__(self, key, value):
.... self[key].append(value)
.... def keys(self):
.... return self._dict.keys()
....
>>> d = OneToMany((pow(i, 13, 4), i) for i in range(10))
>>> d[0]

[0, 2, 4, 6, 8]
>>> d[1]

[1, 5, 9]
>>> d[3]

[3, 7]

I'll have to think about whether it would be worth keeping a class like
this around... It might make working with this kind of data
interactively simpler...

Thanks for the comments!

Steve

Larry Bates 12-17-2004 11:22 PM

Re: expression form of one-to-many dict?
 
Steven,

Suggestion: It is a bad idea to name any variable
"map". When you do, you destroy your ability to call
Python's map function. Same goes for "list", "str",
or any other built-in function.

If you haven't been bitten by this you will, I was.

Larry Bates

Steven Bethard wrote:
> So I end up writing code like this a fair bit:
>
> map = {}
> for key, value in sequence:
> map.setdefault(key, []).append(value)
>
> This code basically constructs a one-to-many mapping -- each value that
> a key occurs with is stored in the list for that key.
>
> This code's fine, and seems pretty simple, but thanks to generator
> expressions, I'm getting kinda spoiled. ;) I like being able to do
> something like the following for one-to-one mappings:
>
> dict(sequence)
>
> or a more likely scenario for me:
>
> dict((get_key(item), get_value(item) for item in sequence)
>
> The point here is that there's a simple sequence or GE that I can throw
> to the dict constructor that spits out a dict with my one-to-one mapping.
>
> Is there a similar expression form that would spit out my one-to-many
> mapping?
>
> Steve


Steven Bethard 12-17-2004 11:54 PM

Re: expression form of one-to-many dict?
 
Larry Bates wrote:
> Suggestion: It is a bad idea to name any variable
> "map". When you do, you destroy your ability to call
> Python's map function. Same goes for "list", "str",
> or any other built-in function.
>
> If you haven't been bitten by this you will, I was.


A good reminder for all the newbies out there.

Sorry, I renamed my variables to simplify the example -- my names
usually look like '<key>_<value>_map' where <key> and <value> describe
the items in the dict. Since the generic example didn't really have a
description for the keys or values, I stripped it down to map. Fine for
the example, but I should have realized it would draw this comment
(mainly because I probably would have posted a similar one myself if I
had seen the example). ;)

Fortunately, after 2+ years with Python, the risk of me being "bitten"
again by this is pretty small. ;)

Actually, it's even smaller now, because I've pretty much removed map
from all my code in favor of list comprehensions, which I find much
easier to read.

Steve

Fernando Perez 12-18-2004 12:22 AM

Re: expression form of one-to-many dict?
 
Steven Bethard wrote:

> Actually, it's even smaller now, because I've pretty much removed map
> from all my code in favor of list comprehensions, which I find much
> easier to read.


While I agree that listcomps are more readable in most cases (and certainly for
all cases with any amount of complexity in the listcomp), I still find that
map is hard to beat for the simple case of a callable foo:

outlist = map(foo,inlist)

is still better in my book, and far more readable, than

outlist = [foo(x) for x in inlist]

The map form, in this case, parses instantly in my brain, while the listcomp
certainly takes a few cycles. And note that I'm not talking about the typing
conciseness, but about the effort for my brain. But maybe I'm just wired
funny :)

Since I tend to have a lot of code like this, I really cringe when I hear of a
desire to do away with map altogether. I know I could rewrite it myself in
all my code, but the beauty of these builtins is that they are always there...

Cheers,

f


Steven Bethard 12-18-2004 12:32 AM

Re: expression form of one-to-many dict?
 
Fernando Perez wrote:
>
> outlist = map(foo,inlist)
>
> is still better in my book, and far more readable, than
>
> outlist = [foo(x) for x in inlist]
>
> The map form, in this case, parses instantly in my brain, while the listcomp
> certainly takes a few cycles. And note that I'm not talking about the typing
> conciseness, but about the effort for my brain. But maybe I'm just wired
> funny :)


Well, different at least. I find the map one harder to parse mentally.
And not for lack of experience with functional programming. But to
each their own. =)

Steve

Fredrik Lundh 12-18-2004 07:24 AM

Re: expression form of one-to-many dict?
 
Steven Bethard wrote:

>> The map form, in this case, parses instantly in my brain, while the listcomp
>> certainly takes a few cycles. And note that I'm not talking about the typing
>> conciseness, but about the effort for my brain. But maybe I'm just wired
>> funny :)

>
> Well, different at least. I find the map one harder to parse mentally.


if you have trouble parsing a function call, I'm glad I don't have to maintain
your Python programs...

</F>




Steven Bethard 12-18-2004 11:00 AM

Re: expression form of one-to-many dict?
 
Fredrik Lundh wrote:
> Steven Bethard wrote:
>
>>>The map form, in this case, parses instantly in my brain, while the listcomp
>>>certainly takes a few cycles. And note that I'm not talking about the typing
>>>conciseness, but about the effort for my brain. But maybe I'm just wired
>>>funny :)

>>
>>Well, different at least. I find the map one harder to parse mentally.

>
> if you have trouble parsing a function call, I'm glad I don't have to maintain
> your Python programs...


I don't know what I said to upset you so, but I do apologize.

If you could tell me what it was about my statement (that I find a list
comprehension to be a clearer description of program flow than a map
application[1]) that so insulted you, I would be glad to avoid such
comments in the future, if it would avoid such vicious replies from you.

Steve

[1] In my mind, the program flow is spelled out explicitly in the list
comprehension and only implicitly in the map application. Thus the list
comprehension is clearer to me.

Terry Reedy 12-18-2004 08:35 PM

Re: expression form of one-to-many dict?
 
In respect to map(func, seq) versus [func(i) for i in seq], for
pre-existing func, 'OP' wrote

>>>>The map form, in this case, parses instantly in my brain, while the
>>>>listcomp
>>>>certainly takes a few cycles. And note that I'm not talking about the
>>>>typing
>>>>conciseness, but about the effort for my brain. But maybe I'm just
>>>>wired
>>>>funny :)


>> Steven Bethard wrote:
>>>Well, different at least. I find the map one harder to parse mentally.

[and]
> [1] In my mind, the program flow is spelled out explicitly in the list
> comprehension and only implicitly in the map application. Thus the list
> comprehension is clearer to me.


For pre-existing func, I slightly prefer the map form because the
sequential program flow is *not* spelled out. So I can more easily see the
sequence items mapped in parallel. On the other hand, I probably prefer
[i-expression for i in seq] to map(lambda i: i-expression, seq) because I
find the (unnecessary) mental construction of a function object to be a
compensating burden.

I can easily imagine that others will find themselves more comfortably on
one side or the other of the mental fence I find myself sitting on ;-).

Terry J. Reedy





All times are GMT. The time now is 05:18 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.