7

Given

 t1 = {{1, 2}, {3, 4}};
 t2 = {{a, b, c}, {e, f}};

I want to add in succession elements of list 2 to list 1 to get:

{{1, 2, a}, {1, 2, b}, {1, 2, c}, {3, 4, e}, {3, 4, f}}

I can do it by:

Flatten[MapThread[Flatten /@ Tuples[{{#1}, #2}] &, {t1, t2}], 1]

as indicated in Thread over list in different levels. This is pretty rough. Any ideas how to do it in a reasonable concise way and easier to understand?

user57467
  • 2,708
  • 6
  • 12

4 Answers4

9

Your method is quite concise.

You can also do:

MapThread[## & @@ Thread[{## & @@ #, #2}] &]@{t1, t2}

Join @@ MapThread[Thread[{## & @@ #, #2}] &] @ {t1, t2}

Join @@ MapThread[Flatten /@ Thread[{##}, List, {2}] &] @ {t1, t2}

Join @@ MapThread[Function[{a, b}, Append[a, #] & /@ b]] @ {t1, t2}

Join @@ Map[Flatten]@*Tuples /@ Thread[{List /@ t1, t2}]

to get

{{1, 2, a}, {1, 2, b}, {1, 2, c}, {3, 4, e}, {3, 4, f}}

And a Halloween special:

enter image description here

☺ = {## & @@ #, #2} /. 
      {♯__, ♯♯ : {__}} :>
       (## & @@ ({♯, #} & /@ ♯♯)) & @@@
    ({##}\[Transpose]) &;

☺[t1, t2]

 {{1, 2, a}, {1, 2, b}, {1, 2, c}, {3, 4, e}, {3, 4, f}}
kglr
  • 394,356
  • 18
  • 477
  • 896
  • 1
    First I thought your last solution is a joke! But it really works! I am still struggling to understand your other solutions but concerning this last one, I think I will come back to you X-mas next year! – user57467 Oct 14 '20 at 10:55
  • & @@@ t1 is equivalent to Flatten[t1]. What is then the equivalent of Flatten[{t1,t2}]? – user57467 Oct 14 '20 at 17:29
  • 1
    @user57467, Apply[## &, {t1, t2}, 2]? – kglr Oct 14 '20 at 20:53
  • @kgIr, I tried hard to analyze your code, but in Thread[{## & @@ #, #2}] & I can't figure out what ##,#, and #2 refer to.Can you explain, please! Sorry for asking dumb questions. – user57467 Oct 17 '20 at 09:26
  • 2
    @user57467, foo = Thread[{## & @@ #, #2}] & is a pure function ( a function with unnamed arguments) that does the same thing as the function bar[x_,y_] := Thread[{Apply[Sequence][x],y}]. The function ##& is the function Sequence, andt he form buz@@x is the same as Apply[buz][x] (see Apply). The symbols # (Slot ), #2,`#3,...represent the first, second,third,... arguments supplied to a function. – kglr Oct 17 '20 at 18:35
  • 1
    ... To see the reason for using Apply[Sequence] on the first argument, let x={2,4,5};y={u,v}; and try Thread[{Apply[Sequence][x],y}] vs Thread[{x,y}]. – kglr Oct 17 '20 at 18:40
  • 1
    ... and see this flash animation on how Thread works on a list of lists. – kglr Oct 17 '20 at 18:44
6

Given:

t1 = {{1, 2}, {3, 4}};
t2 = {{a, b, c}, {e, f}};

ReplacePart can express the transformation reasonably directly:

ReplacePart[t2, {i_,j_} :> Append[t1[[i]], t2[[i,j]]]] // Catenate

(* {{1,2,a},{1,2,b},{1,2,c},{3,4,e},{3,4,f}} *)

The same technique is textually shorter using MapIndexed, but perhaps a little less readable:

MapIndexed[Append[t1[[#2[[1]]]], #] &, t2, {2}] // Catenate

(* {{1,2,a},{1,2,b},{1,2,c},{3,4,e},{3,4,f}} *)

WReach
  • 68,832
  • 4
  • 164
  • 269
5

I also use Outer to construct the list.

t1 = {{1, 2}, {3, 4}};
t2 = {{a, b, c}, {e, f}};
MapThread[
  Outer[Flatten@*List, {#1}, #2, 1]~Flatten~1 &, {t1, t2}]~Flatten~1
Flatten /@ MapThread[Outer[List, {#1}, #2, 1] &, {t1, t2}]~Flatten~2
cvgmt
  • 72,231
  • 4
  • 75
  • 133
4

Or using CartesianProduct from Combinatorica package

t1 = {{1,2},{3,4}};
t2 = {{a,b,c},{e,f}};

Needs["Combinatorica`"]

Flatten /@ Catenate @ MapThread[CartesianProduct,{List[#]& /@ t1,t2}]

billy192
  • 141
  • 2