6

I have two matrices $A$ and $B$ which are the same size. Each element of $A$ is a list of numbers. Each element of $B$ is just a number. How do I insert each element of $B$ into the corresponding list of $A$?

For example say I have:

A = {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}}

$ = \begin{pmatrix} (1,2) & (3,4)\\ (5,6) & (7,8) \\ (9,10) & (11,12) \end{pmatrix}$

and

B = {{0,0},{1,1},{2,2}}

$=\begin{pmatrix} 0 & 0\\1&1\\2&2 \end{pmatrix}$

How do I form:

{{{1,2,0},{3,4,0}},{{5,6,1},{7,8,1}},{{9,10,2},{11,12,2}}}

$ = \begin{pmatrix} (1,2,0) & (3,4,0)\\ (5,6,1) & (7,8,1) \\ (9,10,2) & (11,12,2) \end{pmatrix}$

Thanks very much for any help

Kuba
  • 136,707
  • 13
  • 279
  • 740
Tom
  • 3,416
  • 1
  • 18
  • 33

6 Answers6

10
MapThread[Append, {A, B}, 2] // MatrixForm

enter image description here

mfvonh
  • 8,460
  • 27
  • 42
10
f = Module[{tmp = ConstantArray[0, Dimensions[#1] + {0, 0, 1}]}, 
            tmp[[All, All, ;; -2]] = #1; tmp[[All, All, -1]] = #2; tmp] &;
f[a, b]
(* {{{1, 2, 0}, {3, 4, 0}},
    {{5, 6, 1}, {7, 8, 1}}, 
    {{9, 10, 2}, {11, 12, 2}}}*)

All methods posted so far:

f1 = MapThread[Append, {#1, #2}, 2] &;
f2 = Join[#1, Transpose[{#2}, {3, 1, 2}], 3] &;
f3 = MapThread[{Sequence @@ #1, #2} &, {#1, #2}, 2] &;
f4 = MapThread[Flatten[{##}] &, {#1, #2}, 2] &;
f5 = MapThread[Insert[#1, #2, -1] &, {#1, #2}, 2] &;
f6 = MapThread[Join[#1, {#2}] &, {#1, #2}, 2] &;
f7 = Partition[MapThread[Append, {Flatten[#1, 1], #2 // Flatten}], 2] &;
f8 = Join[#1, Map[List, #2, {-1}], 3] &;
f9 = Module[{tmp = ConstantArray[0, Dimensions[#1] + {0, 0, 1}]}, 
            tmp[[All, All, ;; -2]] = #1; tmp[[All, All, -1]] = #2; tmp] &;

Timings and ByteCounts using Mr.W's test setup:

A = RandomInteger[99, {700, 400, 200}];
B = RandomInteger[99, {700, 400}];
Grid[Prepend[Timing@ByteCount@#[A, B], #] & /@ 
    {f1, f2, f3, f4, f5, f6, f7, f8, f9}, Dividers -> All]~Style~24 (* thanks: Mr.W *)

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896
  • +1 for timings. Regarding the update, why not Sequence @@ Timing @ ByteCount @ #[A, B]? Shorter and clearer IMO. – Mr.Wizard Jun 24 '14 at 22:22
  • Thank you @Mr.W (you should have seen the first version of Grid[...]:)) – kglr Jun 24 '14 at 22:25
  • Hey look, you picked up the Accept. Since you're open to suggestion how about: Grid[Prepend[Timing @ ByteCount @ #[A, B], #] & /@ {f1, f2, f3, f4, f5, f6, f7, f8, f9}, Dividers -> All] ~Style~ 24 – Mr.Wizard Jun 24 '14 at 22:32
  • Thank you againm @Mr.W. Accept is likely to be a mistake -- soon to be corrected now that timings table, with larger fonts, is more readable:) Thomas, thank you .. but are you sure?:) – kglr Jun 24 '14 at 22:50
  • Well it contains the most information for future readers. – Tom Jun 28 '14 at 10:03
9

just a nonpractical variation:

Join[A, Map[List, B, {-1}], 3]
Kuba
  • 136,707
  • 13
  • 279
  • 740
  • +1 for using Join. Actually, this too will preserve packed arrays as above the "MapCompileLength" it will compile. Would you prefer that I delete my answer and include the examples in yours instead? (Though Transpose is still faster I believe.) – Mr.Wizard Jun 24 '14 at 18:37
  • @Mr.Wizard Please do not delete your answer :) Let both of them stay, if not then yours is more valuable :) – Kuba Jun 24 '14 at 18:49
6

Here are some more ways to do what is asked

a = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};
b = {{0, 0}, {1, 1}, {2, 2}};

MapThread[{Sequence @@ #1, #2} &, {a, b}, 2]

MapThread[Flatten[{##}] &, {a, b}, 2]

MapThread[Insert[#1, #2, -1] &, {a, b}, 2]

MapThread[Join[#1, {#2}] &, {a, b}, 2]

and finally, using argument destructuring,

Block[{f},
 f[{x_, y_}, z_] := {x, y, z};
 MapThread[f, {a, b}, 2]]

All of the above return

{{{1, 2, 0}, {3, 4, 0}}, {{5, 6, 1}, {7, 8, 1}}, {{9, 10, 2}, {11, 12, 2}}}

The common thread (pun intended) running through all these examples is that any function accepting a 1st arg matching {x_, y_} and a 2nd arg matching z_ and producing {x, y, z} can be MapThread-ed at level 2 to produce the required result.

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
6

Unlike other answers here the combination of Join and Transpose will preserve a fully packed array:

<< Developer`

A = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}} // ToPackedArray;
B = {{0, 0}, {1, 1}, {2, 2}} // ToPackedArray;

Join[A, Transpose[{B}, {3, 1, 2}], 3] // PackedArrayQ
True

This allows superior speed and memory management:

A = RandomInteger[99, {700, 400, 200}];
B = RandomInteger[99, {700, 400}];

MapThread[Append, {A, B}, 2]          // ByteCount // Timing
Join[A, Transpose[{B}, {3, 1, 2}], 3] // ByteCount // Timing
{0.436, 262108032}

{0.0393, 225120132}


Edit: Kuba's method will also preserve a packed array when given input large enough to invoke compilation according to the value defined in SystemOptions["CompileOptions" -> "MapCompileLength"].

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
5

One solution could be like this:

Partition[MapThread[Append, {Flatten[A, 1], B // Flatten}], 2]
Basheer Algohi
  • 19,917
  • 1
  • 31
  • 78