Minor annoyance

19 05 2007

Map operation on sets isn’t closed, both in Python:

>>> type( map(lambda x: x**2, set([1,2,3,4])) )
<type 'list'>

and Ruby:
>> Set.new([1,2,3,4]).map { |x| x**2 }.class
=> Array

At least Haskell does the right thing:
Main> typeOf( Set.map (\x -> x^2) (Set.fromList([1,2,3,4::Integer])) )
Set Integer

An obvious workaround is to operate on lists and convert to sets once you need them. You have to ask yourself whether it will cause performance problems in your application.




5 responses

20 05 2007
Jay P.

Would you want it closed with a dynamic language though? Considering you can pass in *any* data type to map, as long as it supports the right methods, I don’t see how it could guarantee a closed operation.

I suppose the spec could say “generates a set when passed in a set, and a list otherwise”, but that doesn’t seem very consistent.

20 05 2007

Actually, what I would like to see is (similar to Haskell implementation) a special version of map for sets. There is itertools.imap to return an iterator, standard map to return a list, but no version of map for sets. Having a set of map/filter/reduce optimized for use with sets would be very convenient. Sadly, I don’t have time to implement it myself, so considering pretty low importance of this feature, it probably won’t get implemented at all.

20 05 2007

Just found out that sets support generator expressions, so I can implement map and reduce pretty easily. :-)

def smap(f, s):
    return set(f(x) for x in s)

def sfilter(f, s):
    if f is None:
        f = lambda x: x
    return set(x for x in s if f(x))

Example use:
>>> smap(lambda x: x**2, set([1,2,3,4]))
set([16, 1, 4, 9])
>>> sfilter(lambda x: x > 2, set([1,2,3,4]))
set([3, 4])

Reduce for sets will only make sense for commutative operations, so I left that one out.

22 05 2007

Why don’t you just use itertools.imap ?

>>> from itertools import imap
>>> set(imap(lambda x: x**2, set([1,2,3,4])))
set([16, 1, 4, 9])

22 05 2007

You’re right, itertools will do the job as well. But unless you’re using Python 2.3, the code with generator expressions simply looks better. :-)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: