26

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
Matt
  • 12,848
  • 2
  • 31
  • 53
Nasser
  • 12,849
  • 6
  • 52
  • 104
  • 2
    duplicate question: [Inserting into a 2d list](http://stackoverflow.com/questions/4270802/inserting-into-a-2d-list) – WReach Sep 24 '11 at 13:31
  • @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 Sep 24 '11 at 14:16
  • 2
    [This](http://stackoverflow.com/q/1244782/499167) question is also similar. [There](http://stackoverflow.com/questions/1244782/how-to-prepend-a-column-to-a-matrix/2274679#2274679) [Janus](http://stackoverflow.com/users/212538/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](http://stackoverflow.com/q/7534005/499167) has been treated a lot more harshly than this one as a 'possible duplicate') – 681234 Sep 24 '11 at 19:38
  • @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 Sep 24 '11 at 21:19

5 Answers5

19

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.

Leonid Shifrin
  • 22,449
  • 4
  • 68
  • 100
  • 1
    thanks, I came a little close to your second method, but I was writing a[[All,1]] and that made it hard to go from there, and did not know until now that I could have used a[[All, ;; 1]]. This small difference made it possible to use the output more easily. This really helps to know this cool trick. I am sure this will come handy as I used matrices alot in Mathematica. Thanks again. – Nasser Sep 24 '11 at 08:09
  • I love the first method with a small modification: `MapThread[Insert[#1, #2, j] &, {a, column_vector}]` – Say OL Aug 08 '22 at 10:54
11

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]
ivbc
  • 125
  • 6
Bob Jones
  • 161
  • 2
  • 2
7

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

Sjoerd C. de Vries
  • 16,122
  • 3
  • 42
  • 94
  • 3
    +1. The catch you mentioned was one reason that I didn't use the `Sequence` - based method. Here are two more related links, one very recent:http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/b7303eafccee6d5a, and http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/8d04685fd7283130. I generally have a negative attitude towards `Sequence` - based assignments, for reasons I mentioned in my posts in those threads. The other reason for not using `Sequence` is that this will lead to unpacking for packed matrices. – Leonid Shifrin Sep 24 '11 at 08:47
  • 3
    By the way, the method with `Sequence` will *still* lead to copying, it is just better hidden. When you do `Insert`, copying is done at definition-time. With the `Sequence`- based method, copying is done at run-time, during the `Sequence` - splicing step of evaluation. In this regard, I consider an example of list - building with `Sequence` in the docs for MathLink here: http://reference.wolfram.com/mathematica/tutorial/HandlingListsArraysAndOtherExpressions.html particularly misleading. They stress performance but ignore the fact that this method has quadratic complexity (like `Append`). – Leonid Shifrin Sep 24 '11 at 08:56
4

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.

Phil
  • 815
  • 1
  • 8
  • 15
4

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.

Community
  • 1
  • 1
681234
  • 4,214
  • 2
  • 35
  • 42