6
$\begingroup$

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

$\endgroup$
2
  • $\begingroup$ Are the columns of B always identical as shown in this example? $\endgroup$
    – Mr.Wizard
    Jun 24, 2014 at 18:24
  • $\begingroup$ No, just giving a simple example so I can understand. :) $\endgroup$
    – Tom
    Jun 24, 2014 at 18:48

6 Answers 6

10
$\begingroup$
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

$\endgroup$
5
  • $\begingroup$ +1 for timings. Regarding the update, why not Sequence @@ Timing @ ByteCount @ #[A, B]? Shorter and clearer IMO. $\endgroup$
    – Mr.Wizard
    Jun 24, 2014 at 22:22
  • $\begingroup$ Thank you @Mr.W (you should have seen the first version of Grid[...]:)) $\endgroup$
    – kglr
    Jun 24, 2014 at 22:25
  • $\begingroup$ 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 $\endgroup$
    – Mr.Wizard
    Jun 24, 2014 at 22:32
  • $\begingroup$ 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?:) $\endgroup$
    – kglr
    Jun 24, 2014 at 22:50
  • $\begingroup$ Well it contains the most information for future readers. $\endgroup$
    – Tom
    Jun 28, 2014 at 10:03
10
$\begingroup$
MapThread[Append, {A, B}, 2] // MatrixForm

enter image description here

$\endgroup$
3
  • $\begingroup$ +1... what sort of code is your email addr expressed in? $\endgroup$ Jun 24, 2014 at 14:16
  • $\begingroup$ @alancalvitti brainf*ck :D. Interpreter / generator. $\endgroup$
    – mfvonh
    Jun 24, 2014 at 14:18
  • $\begingroup$ That's the ticket. Thank you user mfvonh. $\endgroup$
    – Tom
    Jun 24, 2014 at 14:21
9
$\begingroup$

just a nonpractical variation:

Join[A, Map[List, B, {-1}], 3]
$\endgroup$
2
  • $\begingroup$ +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.) $\endgroup$
    – Mr.Wizard
    Jun 24, 2014 at 18:37
  • $\begingroup$ @Mr.Wizard Please do not delete your answer :) Let both of them stay, if not then yours is more valuable :) $\endgroup$
    – Kuba
    Jun 24, 2014 at 18:49
6
$\begingroup$

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.

$\endgroup$
6
$\begingroup$

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"].

$\endgroup$
5
$\begingroup$

One solution could be like this:

Partition[MapThread[Append, {Flatten[A, 1], B // Flatten}], 2]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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