23
votes

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
5
duplicate question: Inserting into a 2d list - WReach
@WReach The question you linked is a bit more narrowly formulated, the request there was to add the column at the end (although some solutions there were more general and suited also for this one). - Leonid Shifrin
This question is also similar. There Janus draws attention to the 'trick' of inserting a column of zeros (say) by the ArrayFlatten method as follows: ArrayFlatten@{{a[[All, ;; 1]], 0, a[[All, 2 ;; 3]]}} (It seems to me that a recent question has been treated a lot more harshly than this one as a 'possible duplicate') - 681234
@TomD I think one reason for questions not treated quite on equal grounds is that more people were aware of the previous one as a duplicate (e.g. I did not know that the subject of this one was discussed before in such a similar setting, and surely neither did Sjoerd). That's because lots of folks (myself included) joined mma SO tag relatively recently. OTOH, once the question gets momentum (answers, votes, comments, etc), it starts its own life and closing may no longer be a good option. - Leonid Shifrin

5 Answers

18
votes

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.

10
votes

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

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".

4
votes

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.

4
votes

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.