# How to sum matrix elements based on finding the first (and second) non-zero elements of each row?

I have a matrix:

I would like to sum all the first non-zero elements of each row so that I get a value of

$$25.5317 + 8.85471 + 6.90018 + 32.9436 + ...$$

and so on and simply ignore zero rows.

Similarly I would like to do the same again for the second non-zero elements from each row so that I get:

$$29.1235 + 11.0472 + 41.2639$$

 tbl = RandomChoice[{.5, .1, .05, .05, .05, .05, .05, .05, .05, .05} ->
Range[0, 9], {10, 10}];
tbl//TableForm


Remove all zeros from tbl and add zeros to the right to make a full array:

PadRight[tbl /. (0) -> Sequence[], Automatic] // TableForm


Then sum each column:

 Tr /@ (Transpose@PadRight[tbl /. (0) -> Sequence[], Automatic])
(* {55, 59, 36, 28, 38, 14, 9} *)


Update: To get a matrix with dimensions {nrows, ncolumns} from PadRight change Automatic to {nrows, ncolumns}. So,

 Tr /@ (Transpose@PadRight[tbl /. (0) -> Sequence[], {10,10}])
(* {55, 59, 36, 28, 38, 14, 9, 0 ,0, 0} *)

• Hi @kguler, seems to work but I originally had 5 columns, now after sorting, it is 4 columns? Why is that? I need to maintain the column to be constant. Commented Nov 16, 2012 at 2:27
• @sebastian, to get a matrix with dimensions {nrows, ncolumns} from PadRight change Automatic to {nrows, ncolumns}. (The setting Automatic adds as many columns as needed to remove raggedness.)
– kglr
Commented Nov 16, 2012 at 2:37

Not as nice as the method given by kguler. Nevertheless, as an alternative:

myarray = {{0., 0., 0., 0., 0}, {0., 0., 0., 0., 0},
{0., 0., 0., 25.5317, 29.1235}, {0., 0., 0., 0., 8.85471}, {0., 0.,
0., 0., 0}, {0., 0., 0., 0., 0}, {0., 0., 0., 0., 6.90018}, {0.,
0., 0., 0., 32.9436}, {0., 0., 0., 0., 29.1235}, {0., 0., 0.,
2.47854, 11.0472}, {0., 0., 16.1408, 41.2639, 45.7614}, {0., 0.,
0., 0., 0}, {0., 0., 0., 0., 0}, {0., 0., 0., 0., 0}}


(Using Flatten to transpose a ragged array):

Flatten[Select[#, FreeQ[#, 0. | 0] &] & /@ myarray, {2}]


=>

{{25.5317, 8.85471, 6.90018, 32.9436, 29.1235, 2.47854, 16.1408}, {29.1235, 11.0472, 41.2639}, {45.7614}}

Therefore,

Total /@ Flatten[Select[#, FreeQ[#, 0. | 0] &] & /@ myarray, {2}]


=>

{121.973, 81.4346, 45.7614}

Comparing with kguler's method

tbl = RandomChoice[{.5, .1, .05, .05, .05, .05, .05, .05, .05, .05} ->
Range[0, 9], {10, 10}];
Tr /@ (Transpose@PadRight[tbl /. (0) -> Sequence[], Automatic]) ==
Total /@ Flatten[Select[#, FreeQ[#, 0. | 0] &] & /@ tbl, {2}]


=>

True

Edit

Better, perhaps, is

Total /@ Flatten[DeleteCases[myarray, 0 | 0., 2], {2}]


However, the best variation on the Flatten approach, I recon, is given below (as a comment) by rm -rf:

Total[Flatten[# /. 0 | 0. -> Sequence[], {2}], {2}] &@myarray


=>

{121.973, 81.4346, 45.7614}

• I was about to write an answer with this same approach. It can also be written as: Total[Flatten[# /. 0|0. -> Sequence[], {2}], {2}]&
– rm -rf
Commented Nov 15, 2012 at 18:42
• @rm -rf. That is a nice one! Thanks. Commented Nov 15, 2012 at 19:52
• Tom and @rm-rf, actually I like your method better:).
– kglr
Commented Nov 16, 2012 at 3:12

One can search for the first nonzero element in each row using Cases. Generate a random table:

m = Normal@SparseArray[
Thread@{RandomInteger[{1, 12}, 14], RandomInteger[{1, 6}, 14]} :> RandomReal[], {12, 6}];


and pick the first match in each row:

Flatten[Cases[#, _?(! PossibleZeroQ@# &), 1, 1] & /@ m]


Or extending the Sequence replacement method in kguler's answer:

m /. {0 | 0. -> Sequence[]} /. {} -> Sequence[] /. {x_?NumberQ, ___} :> x

{0.252222, 0.998427, 0.0562231, 0.849365, 0.582891, 0.0896831, 0.31189, 0.524075}


To get the second nonzero element from each row:

m /. {0 | 0. -> Sequence[]} /. {} | {_} -> Sequence[] /. {_?NumberQ, x_, ___} :> x

{0.949761, 0.841579, 0.0275406, 0.500705}


Total then does the summing.

Using 1066's data

mat = {{0., 0., 0., 0., 0}, {0., 0., 0., 0., 0},
{0., 0., 0., 25.5317, 29.1235}, {0., 0., 0., 0., 8.85471}, {0., 0.,
0., 0., 0}, {0., 0., 0., 0., 0}, {0., 0., 0., 0., 6.90018}, {0.,
0., 0., 0., 32.9436}, {0., 0., 0., 0., 29.1235}, {0., 0., 0.,
2.47854, 11.0472}, {0., 0., 16.1408, 41.2639, 45.7614}, {0., 0.,
0., 0., 0}, {0., 0., 0., 0., 0}, {0., 0., 0., 0., 0}};


With Slot and MapApply

sum[m_, n_] :=
Slot[n] & @@@ PadRight[mat //. 0 | 0. | {} :> Nothing] // Total

sum[mat, #] & /@ Range[3]


{121.973, 81.4346, 45.7614}