Stream: helpdesk (published)

Topic: `map!` and `enumerate`


view this post on Zulip Alec (Aug 03 2023 at 03:33):

Is it expected that the last item errors?

a = zeros(3);

map(x -> x[1] + x[2] * 2, enumerate([1, 2, 3]));       # this works
map!(x ->  x * 2, a,[1, 2, 3]);                        # this works
map!(x -> x[1] + x[2] * 2, a,[(1,1),(1,2),(1,3)])      # this works
map!(x -> x[1] + x[2] * 2, a,enumerate([1, 2, 3]));    # method error

I also tried (i,x) -> i + x*2 with the last one, but that didn't work either. collecting the enumeration first does work.

view this post on Zulip Jakob Nybo Nissen (Aug 03 2023 at 13:27):

It looks like weirdly, map! is not defined for arbitrary iterables.
Anyway, IMO, people should default to lazy mapping in most cases: Iterators.map(x -> x[1] + x[2] * 2, enumerate(a)) works just fine

view this post on Zulip Expanding Man (Aug 03 2023 at 17:08):

I think that, in the general case, it's not clear how to do assignment on arbitrary iterables, which is probably why map! is not defined for them. For example, trying to map! from a tuple into a matrix is ambiguous unless you assume some convention for indexing the matrix by 1:n. Probably fine in this case since Julia already has an integer indexing convention for matrices, but it may not generalize well.

view this post on Zulip Brian Chen (Aug 03 2023 at 17:46):

In my mind fewer functions should be defined for general iterables because some of them make rather large and often incorrect assumptions about their inputs. In that light I agree

view this post on Zulip Brian Chen (Aug 03 2023 at 17:48):

But in this particular case, it should be known how to do assignment on the destination since it's an Array?

view this post on Zulip Brian Chen (Aug 03 2023 at 17:49):

A method which takes as source an arbitrary iterable and throws if it doesn't have a known length (which the return type of enumerate does) seems reasonable

view this post on Zulip Expanding Man (Aug 03 2023 at 17:53):

You could always assume an implicit mapping by iteration order, but, map is array-aware in a way I'm not entirely sure I understand, for example

In [2]: map(identity, (1:3) .* (1:4)')
3×4 Matrix{Int64}:
 1  2  3   4
 2  4  6   8
 3  6  9  12

If map! is respecting the array shape of it's arguments, it would be weird if it let you combine them with iterators that dont' have a shape (or have a merely implicit flat shape).

view this post on Zulip Brian Chen (Aug 03 2023 at 18:00):

map is a whole different mess and a can on worms I'd rather not open

view this post on Zulip Brian Chen (Aug 03 2023 at 18:03):

For map!, I think Base has all the right traits to check that the source iterable has the same size/shape as the destination array before proceeding

view this post on Zulip jar (Aug 03 2023 at 18:14):

@Brian Chen You mean in the special case of Iterators.Enumerate{UnitRange{Int64}} or for more general iterators with potentially unknown size?

view this post on Zulip Brian Chen (Aug 03 2023 at 18:16):

They'd need to have a known size since Arrays have a known size. Enumerating a range or an array happens to fit that criteria, yes


Last updated: Oct 02 2023 at 04:34 UTC