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$
2

2 Answers 2

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]}]
$\endgroup$
1
  • $\begingroup$ ..or, as the Wizard reminds, you could use the replacement rule v_?VectorQ :> Transpose[{v}]. $\endgroup$ Nov 13, 2012 at 15:20
4
$\begingroup$

This appears to be faster than J. M.'s functions 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

$\endgroup$
1
  • $\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, 2012 at 15:28

Your Answer

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

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