8
$\begingroup$

I have a matrix:

enter image description here

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$$

$\endgroup$

4 Answers 4

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

enter image description here

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

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

enter image description here

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} *)
$\endgroup$
2
  • $\begingroup$ 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. $\endgroup$ Commented Nov 16, 2012 at 2:27
  • 1
    $\begingroup$ @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.) $\endgroup$
    – kglr
    Commented Nov 16, 2012 at 2:37
6
$\begingroup$

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}

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

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

Mathematica graphics

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.

$\endgroup$
3
$\begingroup$

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}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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