5
$\begingroup$

I suspect this is a duplicate, but I can't seem to find what I'm looking for.

A routine problem I have is the following.

I have a set of data in three (or two, or more) lists:

l1={a1, a2, a3}
l2={b1, b2, b3, b4}
l3={{c1, c2, c3, c4}, {d1, d2, d3, d4}, {e1, e2, e3, e4}}

where c1 is a result under condition {a1, b1}, c2 is a result under condition {a1, b2}, etc.

I want to create the list:

{{a1, b1, c1}, {a1, b2, c2}, {a1, b3, c3},{a1, b4, c4}, {a2, b1, d1}, ...}

in preparation for creating a string to export to a text file.

My current solution:

Map[Transpose[{l2, #}] &, l3]
MapIndexed[Prepend[#1, l1[[#2[[1]]]]] &, %, {2}]
Flatten[%, 1]

This works, but the solution isn't intuitive to me, which makes me think there's a better way.

Is there a preferred approach for this task?

$\endgroup$
7
$\begingroup$

This will generate a nested list, in accordance with l3:

MapThread[Append, {Outer[List, l1, l2], l3}, 2]

{{{a1, b1, c1}, {a1, b2, c2}, {a1, b3, c3}, {a1, b4, c4}}, {{a2, b1, d1}, {a2, b2, d2}, {a2, b3, d3}, {a2, b4, d4}}, {{a3, b1, e1}, {a3, b2, e2}, {a3, b3, e3}, {a3, b4, e4}}}

Flattening once will give you what you want:

Flatten[MapThread[Append, {Outer[List, l1, l2], l3}, 2], 1]

{{a1, b1, c1}, {a1, b2, c2}, {a1, b3, c3}, {a1, b4, c4}, {a2, b1, d1}, {a2, b2, d2}, {a2, b3, d3}, {a2, b4, d4}, {a3, b1, e1}, {a3, b2, e2}, {a3, b3, e3}, {a3, b4, e4}}

If you're not interested in the nested list above, then you can get straight to the result with

MapThread[Append, {Tuples[{l1, l2}], Flatten[l3]}]

{{a1, b1, c1}, {a1, b2, c2}, {a1, b3, c3}, {a1, b4, c4}, {a2, b1, d1}, {a2, b2, d2}, {a2, b3, d3}, {a2, b4, d4}, {a3, b1, e1}, {a3, b2, e2}, {a3, b3, e3}, {a3, b4, e4}}

(in effect, Flattening before MapThreading).

$\endgroup$
  • $\begingroup$ Hmmmm. Tuples and Outer were new to me. I see how they simplified things. Thanks! $\endgroup$ – Brian Feb 22 at 22:10
3
$\begingroup$
Join[Tuples[{l1, l2}], ArrayReshape[l3, {Times @@ Dimensions[l3], 1}], 2]

{{a1, b1, c1}, {a1, b2, c2}, {a1, b3, c3}, ...}

Though if the elements of l3 are list of equal length, then ArrayReshape/Dimension won't work.
To avoid that problem you could write

ArrayReshape[Riffle[Tuples[{l1, l2}], #], {Length[#], 3}] &[Catenate[l3]]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.