Efficient method for Inserting arrays into arrays

7

5

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

Pam

Posted 2014-03-21T15:01:47.830

Reputation: 1 759

1"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. – VF1 – 2014-03-21T15:14:24.073

@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) – rm -rf – 2014-03-21T15:16:04.273

Edited for clarity. Added constraint insertion is by column. – Pam – 2014-03-21T15:17:10.163

Answers

9

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 ;;]]]

Kuba

Posted 2014-03-21T15:01:47.830

Reputation: 129 207

This one's really fast (and the cleanest solution, too) - good job! – VF1 – 2014-03-21T17:01:45.800

@VF1 Great you like it, thanks ;) – Kuba – 2014-03-21T17:36:17.750

I really like this solution. its very clean and does the job well… – Pam – 2014-03-21T17:59:46.067

@Kuba , how can this function be used to add the array/ matrix b after EACH array of the original matrix a? – Titus – 2019-07-25T06:55:45.907

@Titus do you mean after each column of a? – Kuba – 2019-07-25T07:28:39.403

@Kuba almost. I am looking for a way to input rows of 0 in a matrix, such as in the following example ted = Table[Range[3], {3}]; stan2 = ConstantArray[{{0, 0, 0}, {0, 0, 0}}, 3]; Partition[Flatten[Thread[{stan2, ted}]], 3] Having the example for columns as well would help – Titus – 2019-07-25T07:34:23.600

2

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]

VF1

Posted 2014-03-21T15:01:47.830

Reputation: 4 472

VF1. Thanks. I tried the MapThread method as well… I was almost going to accept this as the solution… – Pam – 2014-03-21T18:01:25.930

0

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:

rm -rf

Posted 2014-03-21T15:01:47.830

Reputation: 85 395

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] – VF1 – 2014-03-21T15:34:25.703

0

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

Chris Degnen

Posted 2014-03-21T15:01:47.830

Reputation: 27 033

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. – VF1 – 2014-03-21T17:00:05.707

@VF1 - I wondered. It will be interesting to see the timings. – Chris Degnen – 2014-03-21T18:39:27.337