Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I am trying to use MapIndexed to manipulate a matrix of data but I am having trouble getting the levels parameter to work the way I would like. Suppose that my data looks like this, with every odd column being a count and the even columns being some piece of data:

a = {{11, d11, 21, d21, 31, d31}, 
    {12, d12, 22, d22, 32, d32}, 
    {13, d13, 23, d23, 33, d33}, 
    {14, d14, 24, d24, 34, d34}};

b = {{11, d11, 0, Null, 31, d31}, 
    {12, d12, 0, Null, 32, d32}, 
    {13, d13, 0, Null, 33, d33}, 
    {14, d14, 0, Null, 34, d34}};

c = {{0, Null, 0, Null, 31, d31}, 
    {0, Null, 0, Null, 32, d32}, 
    {0, Null, 0, Null, 0, Null}, 
    {0, Null, 0, Null, 34, d34}};

As you can see, some odd columns will have a zero count and the corresponding data column will be NULL. Edit: I have changed c to reflect some new bits of information about the data. There may be some rows that contain the 0, NULL pattern, but I only want to eliminate columns in which the first row is like this. The first row is a sum of the following rows, and I only want to eliminate a column if it has no data at all. This is why I structured the For loop in the way I did. Based on the responses, I felt I needed to clarify. I'd like to eliminate both the count and data columns any time this is the case. For example, after some operation I'd like to have:

a0 = {{11, d11, 21, d21, 31, d31}, 
     {12, d12, 22, d22, 32, d32}, 
     {13, d13, 23, d23, 33, d33}, 
     {14, d14, 24, d24, 34, d34}};

b0 = {{11, d11, 31, d31}, 
     {12, d12, 32, d32}, 
     {13, d13, 33, d33}, 
     {14, d14, 34, d34}};

c0 = {{31, d31}, 
     {32, d32}, 
     {0, NULL}, 
     {34, d34}};

I accomplished this using a hack with a For loop but this is obviously not the proper way to use Mathematica and I was directed to MapIndexed:

a0 = For[i = 1, i < Length @ a[[1]], i = i + 2, 
         If[a[[1, i]] == 0,
             a = Drop[a, None, {i, i + 1}];
             i = i - 2
         ]
     ];

How can I get a0 with something of this form?:

a0 = MapIndexed[f, a, list];
share|improve this question

4 Answers 4

up vote 2 down vote accepted
 Transpose[c] //. {before___, {0..}, {Null..}, after___} :> {before, after} // Transpose
{
 {31,  d31}, 
 {32,  d32}, 
 { 0, Null}, 
 {34,  d34}
}

Update:

In case of column headers as in the comment below, the patterns in the rule need to modified slightly:

Transpose[c] //. {before___, {_, 0..}, {_, Null..}, after___} :> {before, after} // Transpose
{
 {"h3", "d3"}, 
 {  31,  d31}, 
 {  32,  d32}, 
 {   0, Null}, 
 {  34,  d34}
}
share|improve this answer
    
This line works correctly for the given data, but it does not work if there are column headers like head = {"h1", "d1", "h2", "d2", "h3", "d3"} that I would like to keep. Is there a simple way to work around this to produce f[PrependTo[c, head]] = {{"h3","d3"},{31, d31},{32, d32},{0, Null},{34, d34}} –  Nick Jul 18 at 17:28
    
The update works beautifully on my data set, thank you. –  Nick Jul 18 at 18:37
    
Suppose that instead of only wanting to eliminate columns whose first (non-header) entry is 0, I also would like to eliminate columns whose first (non-header) entry is below a certain threshold - say 1% of the first value in the farthest right column. Can this be done using a similar RuleDelayed? –  Nick Jul 22 at 21:36
    
@Nick I'm not sure what you mean exactly. Why don't you post this as a new question with one or two examples? –  Teake Nutma Jul 23 at 12:26

Here's another way typical for Mathematica:

c //. {a___, _, Null, b___} :> {a, b}
share|improve this answer
    
Could you explain what that command does? I'm a new user. –  Nick Jul 14 at 16:11
    
I'm hesitant to try to replace the documentation because I would not be as eloquent. //. is short for ReplaceRepeated and it will apply the replacement rule to the right until several times until nothing changes (which is necessary if several columns have to be removed). :> is short for RuleDelayed, the distinction between RuleDelayed and Rule is the same as that between Set and SetDelayed. The patterns: ___ matches any sequence of elements, even an empty one. _ matches a single arbitrary element. Reading about these things in the docs is the best way to learn. –  Pickett Jul 14 at 16:17
    
Thank you. Even though this is a good answer, I'd still like to see it done with MapIndexed so I can see an example with that function. –  Nick Jul 14 at 16:26
    
Given OP's example, why not c /. 0 | Null -> Sequence[]? –  rm -rf Jul 14 at 16:35
2  
@Nick I don't think any of the old solution will work in this case. I won't update this answer, but Teake Nutma's answer is in the same spirit as what I wrote but works for your data. –  Pickett Jul 14 at 20:32
c /. (0 | Null) -> Sequence[] // MatrixForm

enter image description here

DeleteCases[MapIndexed[pos, c, {2}, Heads -> False], pos[0 | Null, _], 2] // MatrixForm

enter image description here

share|improve this answer
1  
Given that the OP asked for an explanation of my rule, I think you should at least outline what you're doing in your second piece of (non-trivial) code. –  Pickett Jul 14 at 18:12
    
@eldo It is not clear to me that this provides the desired answer to the OP's question. In particular, for the c matrix, the third row is transformed to {} rather than the desired {0, Null}. –  ecoxlinux Jul 14 at 20:01
1  
@ecoxlinux The question was changed / appended 2 hours after my answer. I think that Pickett's solution handles this case. –  eldo Jul 14 at 20:05

Here is one that seems fast (and only checks the first row, as the OP suggested in the question):

c[[
  All, 
  Flatten@Select[
    Partition[Range@Length@First@c, 2] , 
    c[[1, #]] != {0, Null} &]
]]
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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