Velocity Reviews > enhanced map function

# enhanced map function

Patrick
Guest
Posts: n/a

 03-11-2011
Hi,

The build-in map functions looks quite nice but it requests the
iterables to be of the same length or otherwises will file with None
(most of time fails the function). Just wondering if there are already
enhancement work done with it?

I did some simple code but it will handle list without nesting only.
I am looking for examples that could hand input of "a = [2,3], b=4"
and "a=[1,[2,3],4], b=[5,[6,7,8],9,10]". That means if the nesting
structure is the same, enhanced map function will automatically extend
the shorter list using the last element. Or if the input is a constant
at the first point, then it feeds constant value to all other iterable
combinations.

Any tip is appreciated.
-Patrick.

return x+y

def Bmap(function, *args):
num = 0
for iter in args[0:]:
if num < len(iter):
num = len(iter)

nlist=[]
for i in range(0,num,1):
fargs = []
for iter in args[0:]:
if len(iter) > i:
fargs.append(iter[i])
continue
fargs.append(iter[-1])

nlist.append(function(*fargs))
return nlist

if __name__ == '__main__':
a = [2,3]
b = [4,5,8]

Steven D'Aprano
Guest
Posts: n/a

 03-12-2011
On Fri, 11 Mar 2011 13:00:23 -0800, Patrick wrote:

> Hi,
>
> The build-in map functions looks quite nice but it requests the
> iterables to be of the same length or otherwises will file with None
> (most of time fails the function). Just wondering if there are already
> enhancement work done with it?

That has been fixed in Python 3.1:

[2, 4, 6]

Starting from Python 2.3, the itertools module has had a function imap
with the same behaviour:

[2, 4, 6]

> I did some simple code but it will handle list without nesting only.

Surely that is a good thing. If you have a mix of nested and non-nested
data, that tells me your data is badly organized and needs to be fixed.

> I am looking for examples that could hand input of "a = [2,3], b=4"

Using a small helper function:

import itertools

def make_iterable(obj):
try:
iter(obj)
except TypeError:
obj = itertools.cycle([obj])
return obj

def enhanced_map(func, *args):
args = map(make_iterable, args)
return list(itertools.imap(func, *args))

WARNING: this is dangerous. If none of the arguments are iterable, e.g.
you call enhanced_map(operator.add, 2, 3), this will happily loop forever
building a larger and larger list, until you run out of memory or kill
the Python process.

> and "a=[1,[2,3],4], b=[5,[6,7,8],9,10]". That means if the nesting
> structure is the same, enhanced map function will automatically extend
> the shorter list using the last element.

It isn't clear what you want here. Are you expecting this enhanced map to
recursively drop down into each layer of sub-sequences? That is:

enhanced_map([1, [2,3, [4,5], 6], 7], [8, [7,6, [5,4], 3], 2])

should be the same as

map([1, 2, 3, 4, 5, 6, 7], [8, 7, 6, 5, 4, 3, 2])

or something different?

What do you expect to happen if the sub-sequences don't match up exactly?
E.g. a = [1, 2, [3, 4]]; b = [1, [2, 3], 4]

What do you expect to happen if the shorter list is empty?
E.g. a = [1, 2, [3, 4], 5]; b = [1, 2, [], 3]

arranged in the first place.

--
Steven

Patrick
Guest
Posts: n/a

 03-17-2011
Steven,

Thanks for the info of itertools. It is a great start for me. Overall,
I agree with you that it is really the user data needs to be sorted
out. However, novice users may need help on certain patterns such as
"a=[1,[2,3],4], b=[5,[6,7,8],9,10]". We could just draw our line
saying that similarly nested inputs could be adjusted even though the
members aren't exactly on one-to-one mapping and we won't getting any
deeper for complicated cases such as "a = [1, 2, [3, 4]]; b = [1, [2,
[3,4]], [4,5], 6]".

> enhanced_map([1, [2,3, [4,5], 6], 7], [8, [7,6, [5,4], 3], 2])
> should be the same as
> map([1, 2, 3, 4, 5, 6, 7], [8, 7, 6, 5, 4, 3, 2])

I don't expect the drop. The original nested structure is very
important.

> What do you expect to happen if the sub-sequences don't match up exactly?
> E.g. a = [1, 2, [3, 4]]; b = [1, [2, 3], 4]
>
> What do you expect to happen if the shorter list is empty?
> E.g. a = [1, 2, [3, 4], 5]; b = [1, 2, [], 3]

There are modes called "shortest" and "longest" (and
"AllCombination"/"Cross" which is more complex).

For case a = [1, 2, [3, 4],4]; b = [1, [2, 3], 4,5]

shortest:
a will be adjusted to [1, [3, 4],4]
b will be adjusted to [1, [2, 3],4]

longest:
a will be adjusted to [1, 2,[3, 4],4,4]
b will be adjusted to [1, 1,[2, 3],4,5]

As I said previously, the enhance_map function will only handle
limited "unmatch" cases and the line will need to be drawn carefully.

Thanks
-Patrick.

Steven D'Aprano
Guest
Posts: n/a

 03-18-2011
On Thu, 17 Mar 2011 08:31:28 -0700, Patrick wrote:

> Steven,
>
> Thanks for the info of itertools. It is a great start for me. Overall, I
> agree with you that it is really the user data needs to be sorted out.
> However, novice users may need help on certain patterns such as
> "a=[1,[2,3],4], b=[5,[6,7,8],9,10]".

You have misunderstood me. I'm not saying that you should force the users
to clean up the data (although of course you could do that), but that you
should do so before handing it to map.

Rather than putting all the smarts into enhanced_map, and having it
understand what to do with mismatched nested lists, deep nesting,
integers where you would expect a list, etc., you should write another
function that takes the user's data and adjusts it to some known,
consistent format, and then pass that on to map. Don't have one function
try to do too much.

--
Steven