8
$\begingroup$

Below is my input:

mat = {{0, 0, 0, 0, 0, 1}, {1, 0, 0, 1, 0, 1}, {0, 1, 0, 0, 0, 0}, {0,
     0, 0, 0, 0, 1}, {1, 1, 0, 1, 0, 0}, {0, 0, 0, 1, 0, 1}};

$\quad\quad\left( \begin{array}{cccccc} 0 & 0 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 1 & 0 & 1 \\ 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 \\ 1 & 1 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 1 \\ \end{array} \right) $

I would like to split this matrix by the columns with all-zeros, and in the process remove those columns from the matrix. Expected output below:

output

$\endgroup$
3
  • 4
    $\begingroup$ Please add a code sample not a latex version. And try Transpose /@ (SplitBy[m\[Transpose], MatchQ[#, {0 ..}] &] /. {{0 ..} ..} -> Sequence[]) $\endgroup$
    – Kuba
    Commented Aug 20, 2014 at 8:01
  • 1
    $\begingroup$ @Kuba Nice to see you post something again! $\endgroup$
    – C. E.
    Commented Aug 20, 2014 at 9:54
  • 1
    $\begingroup$ @Pickett Thanks :) that's nice of you, I will try to fully come back around october. I have a lot of boring stuff to do know :/ $\endgroup$
    – Kuba
    Commented Aug 20, 2014 at 20:44

6 Answers 6

4
$\begingroup$

I'm surprised MMA doesn't have something like StringSplit for list, but maybe I haven't looked hard enough. I added the .. to delete multiple all-zero columns after seeing @Kuba's comment. Please upvote his comment instead of my answer since his was the more succinct.

mat = {{0, 0, 0, 0, 0, 1}, {1, 0, 0, 1, 0, 1}, {0, 1, 0, 0, 0, 0}, {0,
     0, 0, 0, 0, 1}, {1, 1, 0, 1, 0, 0}, {0, 0, 0, 1, 0, 1}};

MatrixForm@Transpose@# & /@ 
 DeleteCases[SplitBy[Transpose@mat, # != {0, 0, 0, 0, 0, 0} &], {{0, 0, 0, 0, 0, 0}..}]

Mathematica graphics

$\endgroup$
3
$\begingroup$

Basically, the same idea as seismatica's answer, but with different details.

m =
  {{0, 0, 0, 0, 0, 1},
   {1, 0, 0, 1, 0, 1},
   {0, 1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0, 1},
   {1, 1, 0, 1, 0, 0},
   {0, 0, 0, 1, 0, 1}};

split =
  Transpose /@
    DeleteCases[
      SplitBy[If[Plus @@ # > 0, #] & /@ Transpose[m], # === Null &], 
      {Null}];

A different approach using Reap and Sow.

split = 
  Module[{tag = 1}, 
    Transpose /@ Last @ Reap[If[Plus @@ # > 0, Sow[#, tag], tag++] & /@ Transpose[m]]]

Both of the above produce

MatrixForm /@ split

output

$\endgroup$
3
$\begingroup$

In the spirit of Mathematica 10 I would have written it like this:

Composition[
  DeleteCases[{{0} ..}],
  Map[Transpose],
  SplitBy[#, Unitize@*Total] &,
  Transpose
  ]@mat

{{{0, 0}, {1, 0}, {0, 1}, {0, 0}, {1, 1}, {0, 0}}, {{0}, {1}, {0}, {0}, {1}, {1}}, {{1}, {1}, {0}, {1}, {0}, {1}}}

With rules I would write:

Transpose /@ {Transpose[mat] //. {el__, {0 ..}, rest___} :> Sequence[{el}, {rest}]}

{{{0, 0}, {1, 0}, {0, 1}, {0, 0}, {1, 1}, {0, 0}}, {{0}, {1}, {0}, {0}, {1}, {1}}, {{1}, {1}, {0}, {1}, {0}, {1}}}

The first method assumes numeric matrix elements but the second doesn't.

$\endgroup$
2
$\begingroup$
mat =
  {{0, 0, 0, 0, 0, 1},
   {1, 0, 0, 1, 0, 1},
   {0, 1, 0, 0, 0, 0},
   {0, 0, 0, 0, 0, 1},
   {1, 1, 0, 1, 0, 0},
   {0, 0, 0, 1, 0, 1}};

Using SequenceSplit (new in 11.3)

MatrixForm @* Transpose /@ SequenceSplit[Transpose @ mat, {{0 ..}}]

enter image description here

$\endgroup$
1
$\begingroup$

Here is a function hopefully with some amount of reusability:

splitColsByMask[base_, mask_, key_: 1] := 
  base[[All, #]] & /@ Split[Pick[Range@Length@mask, mask, key], #2 - 1 == # &]

A "mask" for your input:

v = Unitize @ Total @ Unitize @ mat
{1, 1, 0, 1, 0, 1}

Applied:

MatrixForm /@ splitColsByMask[mat, v]

enter image description here

The third parameter "key" defaults to 1; it is the "take" pattern for Part.

$\endgroup$
1
$\begingroup$
mat = {{0, 0, 0, 0, 0, 1}, {1, 0, 0, 1, 0, 1}, {0, 1, 0, 0, 0, 0}, {0,
     0, 0, 0, 0, 1}, {1, 1, 0, 1, 0, 0}, {0, 0, 0, 1, 0, 1}};

SplitBy[Transpose@mat, AllTrue[# == 0 &]] /. {{0 ..}} :> Nothing // 
  Map[Transpose] // Map[MatrixForm]

or

SplitBy[Transpose@mat, Apply[DiscreteDelta]] /. {{0 ..}} :> Nothing //
   Map[Transpose] // Map[MatrixForm]

enter image description here

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