Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

On trying to write this answer I reached the frustrating realization that I didn't have an efficient way to delete a list of columns or deeper level components in a simple way as Part gives.

Given

MatrixForm[m = Partition[Partition[Range[4 4 3], 3], 4]]

Mathematica graphics

I can Delete rows {2,3} by

Delete[m, List /@ {2, 3}] // MatrixForm

Mathematica graphics

But to delete the columns or deeper levels I would need to Transpose twice. For instance using something like this

rDelete[m_, row_, col_] := Delete[
  Transpose[
   Delete[
    Transpose[m]
    , List /@ col
    ]
   ], List /@ row
  ]

Mathematica graphics

On the other hand to get a Part at any level I can easily use

Part[m, All, {1, 4}, {2, 3}] // MatrixForm

Mathematica graphics

Unfortunately, All and Span are not available for Delete.

Question: How can we delete columns or whole higher levels elegantly and efficiently, as we do with Part?

share|improve this question

marked as duplicate by Mr.Wizard list-manipulation Feb 26 at 23:24

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

3  
This removes the second "column" of m: Drop[m, None, {2}, None]. Drop[m, None, None, {2}] gives the complement of your Part[] example. You can judiciously combine this with Map[]/MapAt[] if you need to do several positions, since unlike Delete[], Drop[] can only remove from either a single dimension or a range of dimensions. – J. M. Feb 25 at 16:12
    
@J.M. I guess the problem with Drop is the fact that you need to Map over the list of indexes to delete, as you say. – rhermans Feb 25 at 16:55
    
Also: (43785) – Mr.Wizard Feb 26 at 23:28
up vote 13 down vote accepted

You can actually use Part for that:

ClearAll[delete];
delete[expr_, specs___] :=
  Module[{copy = expr},
    copy[[specs]] = Sequence[];
    copy
  ];

So that for example

delete[m, All, All, 2]

(* 
   {
     {{1, 3}, {4, 6}, {7, 9}, {10, 12}}, 
     {{13, 15}, {16, 18}, {19, 21}, {22, 24}}, 
     {{25, 27}, {28, 30}, {31, 33}, {34, 36}}, 
     {{37, 39}, {40, 42}, {43, 45}, {46, 48}}
   }
*)

Note that this is not exactly equivalent to Delete in all cases, since sequence splicing is an evaluation-time effect, so the results will be different if you delete inside held expressions - in which case the method I suggested may not work.

Here is a version that would probably be free of the mentioned flaw, but will be slower:

ClearAll[deleteAlt];
deleteAlt[expr_, specs___] :=
  Module[{copy = Hold[expr], tag},
    copy[[1, specs]] = tag;
    ReleaseHold@Delete[copy, Position[copy, tag]]
  ];

You can test both on say, Hold[Evaluate[m]], with the spec 1, All, All, 2, to see the difference.

share|improve this answer
    
This opens for me a whole a new understanding of Sequence. Very clever! +1 – rhermans Feb 25 at 16:11
7  
The Sequence[] is replaceable with Nothing in version 10.2, I suppose. Speaking of which: MapAt[Nothing, m, {All, All, 2}]. – J. M. Feb 25 at 16:15
    
@J.M. I am aware of Nothing, but haven't yet gained extensive experience with it, unlike with Sequence. As to MapAt, this is a possibility, but it was known to have efficiency issues in the past, for large number of positions mapped. I didn't have the time to check it now, so I didn't go that way - for in-place assignments with Part, it has been known that it has excellent efficiency in all cases. – Leonid Shifrin Feb 25 at 16:24
1  
I don't want to move the goalpost, I'm grateful for your answer and the code is unambiguous. What I was expecting (naively?) is deleted columns, rows and higher orders all across the array, like in my example with rDelete, where all the elements have the same length. But this already solves most of what I wanted nicely. – rhermans Feb 25 at 18:41
1  
@rhermans This is then different semantics. Here is a version that works that way: ClearAll[delete2];delete2[expr_, part_, rest___] :=Module[{copy = expr}, copy[[part]] = Sequence[];Map[delete2[#, rest] &, copy]]; delete2[expr_] := expr;. But it won't be as efficient as the ones I posted before. – Leonid Shifrin Feb 25 at 19:04

You may use ReplacePart and Nothing with Blank (_) for All.

Delete second entry of all submatrices

ReplacePart[m, {_, _, 2} -> Nothing] // MatrixForm

enter image description here

Delete last column

ReplacePart[m, {_, -1} -> Nothing] // MatrixForm

enter image description here

and so on.

Hope this helps.

share|improve this answer
    
Thanks, it does partially. How do you deal with list of columns to delete? – rhermans Feb 25 at 17:08
2  
@rhermans Alternatives : ReplacePart[m, {_, 2 | 3} -> Nothing] // MatrixForm. – Edmund Feb 25 at 17:21

Not the answer you're looking for? Browse other questions tagged or ask your own question.