Nasser
Nasser

Reputation: 13173

How to insert a column into a matrix, the correct Mathematica way

I think Mathematica is biased towards rows not columns.

Given a matrix, to insert a row seems to be easy, just use Insert[]

(a = {{1, 2, 3}, {4, 0, 8}, {7 , 8, 0}}) // MatrixForm

1   2    3
4   0    8
7   8    0

 row = {97, 98, 99};
(newa = Insert[a, row, 2]) // MatrixForm

1   2   3
97  98  99
4   0   8
7   8   0

But to insert a column, after some struggle, I found 2 ways, I show below, and would like to ask the experts here if they see a shorter and more direct way (Mathematica has so many commands, and I could have overlooked one that does this sort of thing in much direct way), as I think the methods I have now are still too complex for such a basic operation.

First method

Have to do double transpose:

a = {{1, 2, 3}, {4, 0, 8}, {7 , 8, 0}}
column = {97, 98, 99}
newa = Transpose[Insert[Transpose[a], column, 2]]

1   97  2   3
4   98  0   8
7   99  8   0

Second method

Use SparseArray, but need to watch out for index locations. Kinda awkward for doing this:

(SparseArray[{{i_, j_} :> column[[i]] /; j == 2, {i_, j_} :> a[[i, j]] /; j == 1, 
              {i_, j_} :> a[[i, j - 1]] /; j > 1}, {3, 4}]) // Normal

1   97  2   3
4   98  0   8
7   99  8   0

The question is: Is there a more functional way, that is little shorter than the above? I could ofcourse use one of the above, and wrap the whole thing with a function, say insertColumn[...] to make it easy to use. But wanted to see if there is an easier way to do this than what I have.

For reference, this is how I do this in Matlab:

EDU>> A=[1 2 3;4 0 8;7 8 0]
A =
     1     2     3
     4     0     8
     7     8     0

EDU>> column=[97 98 99]';

EDU>> B=[A(:,1) column A(:,2:end)]

B =
     1    97     2     3
     4    98     0     8
     7    99     8     0

Upvotes: 26

Views: 28943

Answers (5)

Bob Jones
Bob Jones

Reputation: 161

You can use Join with a level specification of 2 along with Partition in subsets of size 1:

a = {{1, 2, 3}, {4, 0, 8}, {7 , 8, 0}}
column = {97, 98, 99}
newa = Join[a,Partition[column,1],2]

Upvotes: 11

681234
681234

Reputation: 4284

I originally posted this as a comment (now deleted)

Based on a method given by user656058 in this question (Mathematica 'Append To' Function Problem) and the reply of Mr Wizard, the following alternative method of adding a column to a matrix, using Table and Insert, may be gleaned:

(a = {{1, 2, 3}, {4, 0, 8}, {7, 8, 0}});
column = {97, 98, 99};

Table[Insert[a[[i]], column[[i]], 2], {i, 3}] // MatrixForm

giving

enter image description here

Similarly, to add a column of zeros (say):

Table[Insert[#[[i]], 0, 2], {i, Dimensions[#][[1]]}] & @ a 

As noted in the comments above, Janus has drawn attention to the 'trick' of adding a column of zeros by the ArrayFlatten method (see here)

ArrayFlatten[{{Take[#, All, 1], 0, Take[#, All, -2]}}] & @ 
  a // MatrixForm

Edit

Perhaps simpler, at least for smaller matrices

(Insert[a[[#]], column[[#]], 2] & /@ Range[3]) // MatrixForm

or, to insert a column of zeros

Insert[a[[#]], 0, 2] & /@ Range[3]

Or, a little more generally:

Flatten@Insert[a[[#]], {0, 0}, 2] & /@ Range[3] // MatrixForm

May also easily be adapted to work with Append and Prepend, of course.

Upvotes: 4

Phil
Phil

Reputation: 815

I usually just do like this:

In: m0 = ConstantArray[0, {3, 4}]; 
    m0[[All, {1, 3, 4}]] = {{1, 2, 3}, {4, 0, 8}, {7, 8, 0}}; 
    m0[[All, 2]] = {97, 98, 99}; m0 

Out: 
    {{1, 97, 2, 3}, {4, 98, 0, 8}, {7, 99, 8, 0}}

I don't know how it compare in terms of efficiency.

Upvotes: 4

Sjoerd C. de Vries
Sjoerd C. de Vries

Reputation: 16232

I think I'd do it the same way, but here are some other ways of doing it:

-With MapIndexed

newa = MapIndexed[Insert[#1, column[[#2[[1]]]], 2] &, a]

-With Sequence:

newa = a;
newa[[All, 1]] = Transpose[{newa[[All, 1]], column}];
newa = Replace[a, List -> Sequence, {3}, Heads -> True]

Interestingly, this would seem to be a method that works 'in place', i.e. it wouldn't really require a matrix copy as stated in Leonid's answer and if you print the resulting matrix it apparently works as a charm.

However, there's a big catch. See the problems with Sequence in the mathgroup discussion "part assigned sequence behavior puzzling".

Upvotes: 8

Leonid Shifrin
Leonid Shifrin

Reputation: 22579

Your double Transpose method seems fine. For very large matrices, this will be 2-3 times faster:

MapThread[Insert, {a, column, Table[2, {Length[column]}]}]

If you want to mimic your Matlab way, the closest is probably this:

ArrayFlatten[{{a[[All, ;; 1]], Transpose[{column}], a[[All, 2 ;;]]}}]

Keep in mind that insertions require making an entire copy of the matrix. So, if you plan to build a matrix this way, it is more efficient to preallocate the matrix (if you know its size) and do in-place modifications through Part instead.

Upvotes: 19

Related Questions