7
$\begingroup$

Having the need to attach a column to a matrix or to join matrices to make longer rows is an operation that I use very frequently and I find the Join function ideal for these cases.

m1 = {{10, 11, 12}, {21, 22, 23}};
m2 = {100, 101};

(* Join matrices to make longer rows: *)
Join[m1, m1, 2]
(* --> {{10, 11, 12, 10, 11, 12}, {21, 22, 23, 21, 22, 23}} *)

(* Attach a column to a matrix *)
Join[m1, List /@ m2, 2]
(* --> {{10, 11, 12, 100}, {21, 22, 23, 101}} *)

(* Join two columns to make a matrix *)
Join[List /@ m2, List /@ m2, 2]
(* --> {{100, 100}, {101, 101}} *)

However, I wanted to define my own function that would simplify the notation needed to reach my goal:

columnAttach[a1_List, a2_List] := 
  Join[If[VectorQ[a1], List /@ a1, a1], 
  If[VectorQ[a2], List /@ a2, a2], 2]

columnAttach[m1, m1]
(* --> {{10, 11, 12, 10, 11, 12}, {21, 22, 23, 21, 22, 23}} *)
columnAttach[m1, m2]
(* --> {{10, 11, 12, 100}, {21, 22, 23, 101}} *)
columnAttach[m2, m2]
(* --> {{100, 100}, {101, 101}} *)

This works as expected, but I would like to generalize it a bit. For instance, Join can take a list of vectors/matrices of any length:

Join[m1, m1, List /@ m2, List /@ m2, 2]
(* --> {{10, 11, 12, 10, 11, 12, 100, 100},
  {21, 22, 23, 21, 22, 23, 101, 101}} *)

How can I adapt my columnAttach function to achieve the same flexibility?

$\endgroup$
6
$\begingroup$

One possibility:

columnAttach[ak__List] := Join[##, 2] & @@ Replace[{ak}, v_?VectorQ :> List /@ v, 1]

columnAttach[{{10, 11, 12}, {21, 22, 23}}, {100, 101}, {{10, 11, 12}, {21, 22, 23}},
             {100, 101}, {100, 101}]
   {{10, 11, 12, 100, 10, 11, 12, 100, 100},
    {21, 22, 23, 101, 21, 22, 23, 101, 101}}

Alternatively:

columnAttach[ak__List] := ArrayFlatten[{Replace[{ak}, v_?VectorQ :> List /@ v, 1]}]
| improve this answer | |
$\endgroup$
  • $\begingroup$ ..or, as the Wizard reminds, you could use the replacement rule v_?VectorQ :> Transpose[{v}]. $\endgroup$ – J. M.'s discontentment Nov 13 '12 at 15:20
4
$\begingroup$

This appears to be faster than J. M.'s funcions in all cases on my system:

columnAttach2[ak__List] := 
  Replace[Unevaluated@Join[ak, 2], v_?VectorQ :> {v}\[Transpose], 1]

Timings, using J. M.'s Join function (which tested faster):

SetAttributes[timeAvg, HoldFirst]

timeAvg[func_] := 
  Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

m1 = RandomInteger[999, {50, 100}];
m2 = RandomInteger[999, 50];

columnAttach[m1, m2, m2, m1, m2, m1] // timeAvg

columnAttach2[m1, m2, m2, m1, m2, m1] // timeAvg

0.00019968

0.0000141696

| improve this answer | |
$\endgroup$
  • $\begingroup$ Correction: it is no faster but also no slower than J. M.'s code for non-packed arrays but apparently always faster with packed arrays. $\endgroup$ – Mr.Wizard Nov 13 '12 at 15:28

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.