8
$\begingroup$

This is strongly related to the following Questions:

I am looking for an efficient method to insert an array into an array. Let’s assume that both arrays have similar number of rows. Let’s further assume insertion is by column.

a = {{a1, b1, c1, d1, e1}, {a2, b2, c2, d2, e2}, {a3, b3, c3, d3, e3}}; (*example may be larger*)
b = {{x1, y1, z1}, {x2, y2, z2}, {x3, y3, z3}}; (*example may be larger*)

Q1: What is the fastest method to insert b into a at a position p. Let’s assume that both arrays have similar number of rows. Let’s further assume insertion is by column.

My current method is as follows:

insertarray[a_, b_, pos_] :=
FlattenAt[
Transpose@Insert[Transpose@a, b[[##]], pos ] & [Range[Length@a]], 
Table[{i, pos}, {i, 1, Length@a}]];

which allows me to do

insert array

Q2: Some times I have to intersperse columns of b into a at multiple positions. How do I best extend insertarray so that:

insertarray[a,b,{1,2,5}]//MatrixForm

enter image description here

$\endgroup$
3
  • 1
    $\begingroup$ "Insertion" is not very well defined as shown unless a and b both have the same length. If this is the case, you should tell everyone that constraint. $\endgroup$
    – VF1
    Mar 21, 2014 at 15:14
  • $\begingroup$ @VF1 a and b both have the same number of column elements... but yes, it would be better to be explicit whether the insertion is by row or column (esp. with square matrices) $\endgroup$
    – rm -rf
    Mar 21, 2014 at 15:16
  • $\begingroup$ Edited for clarity. Added constraint insertion is by column. $\endgroup$
    – Pam
    Mar 21, 2014 at 15:17

4 Answers 4

10
$\begingroup$

Q1

Join[a[[;; , ;; 1]], b, a[[;; , 2 ;;]], 2]

enter image description here

One may want to create function

insCol[a_, b_, n_] := Join[a[[;; , ;; n - 1]], b, a[[;; , n ;;]], 2]

insRow[a_, b_, n_] := Join[a[[;; n - 1]], b, a[[n ;;]]]
$\endgroup$
6
  • $\begingroup$ This one's really fast (and the cleanest solution, too) - good job! $\endgroup$
    – VF1
    Mar 21, 2014 at 17:01
  • $\begingroup$ @VF1 Great you like it, thanks ;) $\endgroup$
    – Kuba
    Mar 21, 2014 at 17:36
  • $\begingroup$ I really like this solution. its very clean and does the job well… $\endgroup$
    – Pam
    Mar 21, 2014 at 17:59
  • $\begingroup$ @Kuba , how can this function be used to add the array/ matrix b after EACH array of the original matrix a? $\endgroup$
    – Titus
    Jul 25, 2019 at 6:55
  • $\begingroup$ @Titus do you mean after each column of a? $\endgroup$
    – Kuba
    Jul 25, 2019 at 7:28
2
$\begingroup$

After a few attempts, the following gives a noticeable if unremarkable improvement over insertarray:

columnInsert[a_, b_, pos_] := 
  MapThread[Join[#1[[;; pos - 1]], #2, #1[[pos ;;]]] &, {a, b}];

Your second functionality doensn't actually need anything fancy, just some swaps afterwards:

SetAttributes[columnInsert`swap, HoldFirst];
columnInsert`swap[mat_, first_, list_] :=
 Module[{i = first}, 
  Scan[columnInsert`tmp = mat[[All, i]]; 
     mat[[All, i++]] = mat[[All, #]]; 
     mat[[All, #]] = columnInsert`tmp; &, list]; mat]
columnInsert[a_, b_, pos_List] := 
 Module[{res = columnInsert[a, b, First@pos]},
  columnInsert`swap[res, First@pos, pos]; res]
$\endgroup$
1
  • $\begingroup$ VF1. Thanks. I tried the MapThread method as well… I was almost going to accept this as the solution… $\endgroup$
    – Pam
    Mar 21, 2014 at 18:01
0
$\begingroup$

I haven't had a chance to test if this is faster (probably not), but I find it easier to read:

Block[{x, T = Transpose}, Insert[T@a, x, 2] /. x -> Sequence @@ T@b // T]

or alternately:

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

Both give the following:

$\endgroup$
1
  • $\begingroup$ You beat me to the second one. I didn't find it much faster, though. One thing that sped it up slightly is Flatten[..., 1] $\endgroup$
    – VF1
    Mar 21, 2014 at 15:34
0
$\begingroup$

Inserting b at column p :-

a = {{a1, b1, c1, d1, e1}, {a2, b2, c2, d2, e2}, {a3, b3, c3, d3, e3}};
b = {{x1, y1, z1}, {x2, y2, z2}, {x3, y3, z3}};

p = 4;

c = ReleaseHold@MapThread[Insert, {a, Hold[Sequence @@ #] & /@ b, Table[p, {Length@a}]}];

MatrixForm[c]

enter image description here

$\endgroup$
2
  • $\begingroup$ I tried something along these lines, but I found the additional ReleaseHold was too expensive - the whole expression needed to be traversed again for Holds. $\endgroup$
    – VF1
    Mar 21, 2014 at 17:00
  • $\begingroup$ @VF1 - I wondered. It will be interesting to see the timings. $\endgroup$ Mar 21, 2014 at 18:39

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.