# Using levels in MapIndexed

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

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}
}
-
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 '14 at 17:28
The update works beautifully on my data set, thank you. – Nick Jul 18 '14 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 '14 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 '14 at 12:26

Here's another way typical for Mathematica:

c //. {a___, _, Null, b___} :> {a, b}
-
Could you explain what that command does? I'm a new user. – Nick Jul 14 '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. – C. E. Jul 14 '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 '14 at 16:26
Given OP's example, why not c /. 0 | Null -> Sequence[]? – R. M. Jul 14 '14 at 16:35
@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. – C. E. Jul 14 '14 at 20:32
c /. (0 | Null) -> Sequence[] // MatrixForm

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

-
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. – C. E. Jul 14 '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 '14 at 20:01
@ecoxlinux The question was changed / appended 2 hours after my answer. I think that Pickett's solution handles this case. – eldo Jul 14 '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} &]
]]
-