# All possible 2d-list index tuples according to some "picking charts"

I have $$L$$ a 2d list, and $$P$$ a list of lists of $$L$$ 1d-index.
Lists in $$P$$ should be seen as "$$L$$-picking charts".
Let $$(p_{i,1},p_{i,2},\dots,p_{i,n})$$ be the $$i$$-th element of $$P$$, it's meaning will be:

• pick a first object from the $$p_{i,1}$$-th list in $$L$$
• pick a second object from the $$p_{i,2}$$-th list in $$L$$
• ...
• pick a last object from the $$p_{i,n}$$-th list in $$L$$

So for each element in $$P$$ I want to create all possible tuples of $$L$$ 2d-index accordingly to the criteria above.
($$L$$ objects are completely irrelevant, what matters is just their length... But of course, without a bit of context it would have seemed a weird problem)

L = {{1,2,3,4,5}, {13,17,19}, {81,-144,0,-6}, {0,1}, {1729}, {4,6,10,16,26}};

picker[P_] :=
Module[{ranges, picked = {}},
ranges = MapAt[Length@L[[#]]&, P, {All, All}];
Do[
picked = Join[picked, Transpose[{P[[i]], #}]&/@Tuples[ Range/@ranges[[i]] ]]
, {i, Length@P}];
picked
]

picker[{{3,4},{2,4,4,5}}]


{{{3, 1}, {4, 1}}, {{3, 1}, {4, 2}}, {{3, 2}, {4, 1}}, {{3, 2}, {4, 2}}, {{3, 3}, {4, 1}}, {{3, 3}, {4, 2}}, {{3, 4}, {4, 1}}, {{3, 4}, {4, 2}}, {{2, 1}, {4, 1}, {4, 1}, {5, 1}}, {{2, 1}, {4, 1}, {4, 2}, {5, 1}}, {{2, 1}, {4, 2}, {4, 1}, {5, 1}}, {{2, 1}, {4, 2}, {4, 2}, {5, 1}}, {{2, 2}, {4, 1}, {4, 1}, {5, 1}}, {{2, 2}, {4, 1}, {4, 2}, {5, 1}}, {{2, 2}, {4, 2}, {4, 1}, {5, 1}}, {{2, 2}, {4, 2}, {4, 2}, {5, 1}}, {{2, 3}, {4, 1}, {4, 1}, {5, 1}}, {{2, 3}, {4, 1}, {4, 2}, {5, 1}}, {{2, 3}, {4, 2}, {4, 1}, {5, 1}}, {{2, 3}, {4, 2}, {4, 2}, {5, 1}}}

The code works, but it seems a bit too sophisticated, is there a more elegant solution?
N.B.: The function should return all the tuples in one common list and not in Length@P separated lists

I could feel it in my bones that there was a compact way of doing this.

picker[pList_] := Tuples@MapIndexed[#2 &, L, {-1}][[#]] & /@ pList // Catenate

• Amazing! Here's why I asked, you should definitely try Code Golf! Just a minor hassle: I'd like to have all the tuples in one list, where would you add Flatten? Jan 25 at 19:32
• Sorry, my bad I didn't test your code... It returns the expected number of element, but are not in the requested form Jan 25 at 19:57
• @DomenicoModica After postfixing Catenate, I believe the output is in the desired structure of a list of pairs of pairs as it matches your given output. Jan 25 at 20:14
• No I mean that the return index themselves are wrong, they are not lists of pairs Jan 26 at 0:41
• Ok, I've found the error, it should be MapIndexed[#2 &, L, {2}] not ...{-1} because L can contain any kind of more deeply nested object, here's why it didn't work with my actual list Jan 26 at 0:49

Here is a somewhat more MMA like implementation:

picker[d_] := Module[{t},
Function[x, t = Tuples[Range /@ (Length[L[[#]]] & /@ x)];
Transpose[{x, #}] & /@ t
] /@ d
]

picker[{{3, 4}, {2, 4, 4, 5}}]

• A lot better, thanks, I was unaware on how to nest anonymous function Jan 25 at 18:27
• I want all the tuple in one same list, should I add Flatten[#,1]&@(Function[...]/@d)? Jan 25 at 19:24
• You could write: ... t = Transpose[{x, #}] & /@ t] /@ d ; Flatten[t, 1] ] Jan 25 at 19:40
• It doesn't seem to work Jan 25 at 20:01
• Do not worry. t is first used inside Function". However, when "Map" and "Function are done it is used to save the result. "Double use" ): Jan 26 at 9:00

Thanks to both the answers I've come up with the best mix of the two (I suppose...)

picker[P_] := Tuples[Function[x, {x, #} & /@ Range@Length@L[[x]]] /@ #] & /@ P // Catenate


Here's a snippet to test them

picker1[P_] := Function[x, Transpose[{x, #}] & /@ Tuples[Range /@ (Length[L[[#]]] & /@ x)]] /@ P
picker2[P_] := Tuples@MapIndexed[#2 &, L, {2}][[#]] & /@ P
picker3[P_] := Tuples[Function[x, {x, #} & /@ Range@Length@L[[x]]] /@ #] & /@ P

With[{Llen = 100, lmaxlen = 10, Plen = 10, pmaxlen = 7},
L = Table[RandomInteger[100, RandomInteger[{1, lmaxlen}]], Llen];
P = Table[RandomInteger[{1, Llen}, RandomInteger[{1, pmaxlen}]], Plen];
]

{Equal @@ (#[P] & /@ #), First@Timing@Do[#[P], {100}] & /@ #} &@{picker1, picker2, picker3}


Some results

{True, {11.9219, 0.921875, 0.59375}}
{True, {5.328125, 0.546875, 0.265625}}
{True, {23.1875, 1.46875, 1.21875}}