Non allocating tuple transformations which include index

When one is working with tuples, what is the idiomatic way to do operations, when it is necessary to use element indices?

For example, consider that there is a tuple

t = (0.1, 0.2, 0.3, 0.4)

and it should be transformed as t[i] -> i * t[i]^2. More or less obvious solutions are not working, since

map(x -> x[1]*x[2]^2, pairs(t))

throws an error ERROR: map is not defined on dictionaries and

map(x -> x[1]*x[2]^2, enumerate(t))

works fine, but it returns Vector instead of tuple and so it allocates.

Another example is

t1 = (0.1, 0.2, 0.3, 0.4)
t2 = (0.1, 0.1, 0.5, 0.5)

and I need to map it to a tuple of tuples, i.e. ((0.1, 0.1), (0.2, 0.1), (0.3, 0.5), (0.4, 0.5)).

map(identity, zip(t1, t2))

and the like are allocating for the same reason as they do in enumerate case.

I did something like

function indexmap(f, t, i = 1)
    length(t) == 1 && return (f(first(t), i), )
    (f(first(t), I), indexmap(f, Base.tail(t), i + 1)...)
end

but it looks hackish to me and I think that I am missing something obvious.

Maybe look at ntuple (Sorry for being brief, am on phone)

3 Likes

Sure, you are right! I knew that it was going to be something obvious.

Happy easter :slight_smile:

In case someone is interested in implementation details, first question can be solved with

ntuple(i -> i * t[i]^2, length(t))

and second is

ntuple(i -> (t1[i], t2[i]), length(t1))

Of course, it’s a user responsibility to validate that length(t1) == length(t2).

2 Likes