Convert single index into the multiple indices of a tensor product basis

An alternative is to use MixedRadix computations, where the radices are the array dimensions, and taking care of displacements to start at 1 instead of 0. This allows handling one index at a time.

In[1]:= radices = MixedRadix[{2, 3, 2}];

In[2]:= PadLeft[IntegerDigits[#, radices], 3] & /@ Range[0, 11] + 1
Out[2]= {{1, 1, 1}, {1, 1, 2}, {1, 2, 1}, {1, 2, 2}, {1, 3, 1}, {1, 3, 2}, {2, 1, 1}, {2, 1, 2}, {2, 2, 1}, {2, 2, 2}, {2, 3, 1}, {2, 3,2}}

In[3]:= FromDigits[# - 1, radices] + 1 & /@ %
Out[3]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}

Your first method seems fine to me. I came up with this without noticing it is similar to yours,

indexToTensorIndices[idx_Integer, lengths_] := 
 Join[1 + Quotient[idx, #] & /@ (Reverse@
     FoldList[Times, Most@Reverse@lengths]), {Mod[idx, Last@lengths]}]

On extremely large lists of indices it is a bit faster than yours, but yours is pretty fast also.


You could use TuplesFunction from my answer to Lazy form of Tuples/Outer to loop over list of lists. I won't bother to repeat the definition here as it is a bit long. For the OP example:

tf = TuplesFunction[{Range[2], Range[3], Range[2]}];

tf[Range[12]]

{{1, 1, 1}, {1, 1, 2}, {1, 2, 1}, {1, 2, 2}, {1, 3, 1}, {1, 3, 2}, {2, 1, 1}, {2, 1, 2}, {2, 2, 1}, {2, 2, 2}, {2, 3, 1}, {2, 3, 2}}

Here is a timing comparison of TuplesFunction with the OP solution:

r1 = indexToTensorIndices[#, {1000, 2000, 3000}]& /@ Range[10^6+1, 10^6+1000]; //RepeatedTiming

tf = TuplesFunction[{Range[1000], Range[2000], Range[3000]}];
r2 = tf[10^6+1 ;; 10^6+1000]; //RepeatedTiming

r1 === r2

{0.013, Null}

{0.0001, Null}

True

Quite a bit faster.