9
$\begingroup$

I have a list like this:

l={{12}, {}, {}, {}, {}, {70}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, \
{}, {4}, {}, {}, {10}, {}, {}, {}, {}, {}, {1}, {36}, {}, {}, {}, \
{87}, {60}, {}, {58}, {3, 16}, {}, {56}, {75}, {14, 53}, {}, {30}, {}, {84}, {}, {59}, {35, 45, 68}};

I want to substitute the sequences of {} with their run-lengths:

compact[l]=={{12}, 4, {70}, 11, {4}, 2, {10}, 5, {1}, {36}, 3, \
{87}, {60}, 1, {58}, {3, 16}, 1, {56}, {75}, {14, 
  53}, 1, {30}, 1, {84}, 1, {59}, {35, 45, 68}}
$\endgroup$
3
  • $\begingroup$ How big are the lists this will be used on? Can we find other 6 solutions? Would anybody be willing to work out some benchmarks of the many solutions I hope we will see here? $\endgroup$
    – rhermans
    Feb 16 at 14:09
  • $\begingroup$ Sequence functions aren't going to be competitors @rhermans. $\endgroup$
    – Syed
    Feb 16 at 14:11
  • $\begingroup$ @Syed let the race begin! 🏁 $\endgroup$
    – rhermans
    Feb 16 at 14:16

4 Answers 4

13
$\begingroup$
l = {{12}, {}, {}, {}, {}, {70}, {}, {}, {}, {}, {}, {}, {}, {}, {}, \
{}, {}, {4}, {}, {}, {10}, {}, {}, {}, {}, {}, {1}, {36}, {}, {}, {}, \
{87}, {60}, {}, {58}, {3, 16}, {}, {56}, {75}, {14, 
    53}, {}, {30}, {}, {84}, {}, {59}, {35, 45, 68}};

SequenceReplace[l, k : {{} ..} :> Length@k]

{{12}, 4, {70}, 11, {4}, 2, {10}, 5, {1}, {36}, 3, {87}, {60}, 1,
{58}, {3, 16}, 1, {56}, {75}, {14, 53}, 1, {30}, 1, {84}, 1, {59}, {35, 45, 68}}

$\endgroup$
12
$\begingroup$

You can also use a composition of Split, ReplaceAll and Join as follows:

ClearAll[compacT]
compacT = Apply[Join] @* ReplaceAll[ x : {{} ..} :> {Length[x]}] @* Split;

compacT @ l

{{12}, 4, {70}, 11, {4}, 2, {10}, 5, {1}, {36}, 3, {87}, {60}, 1, {58}, {3, 16}, 1, {56}, {75}, {14, 53}, 1, {30}, 1, {84}, 1, {59}, {35, 45, 68}}

This seems to be faster than SequenceReplace for long input lists.

$\endgroup$
6
$\begingroup$

Split and conquer

Here I exploit the split functions

Using Split, Map (/@) and If

 compactRH1[l_] := If[ First[#]=={}, Length[#],  Sequence@@# ]& /@ Split[l]

Using SequenceSplit and Flatten

     compactRH2[l_] := Flatten[SequenceSplit[l,x:{{} ..}:>Length[x]],1]
$\endgroup$
3
$\begingroup$

Using SplitBy and If:

Join @@ (If[Total @@ # === 0, {Length[#]}, #] & /@ (SplitBy[l, Length]))

(*{{12}, 4, {70}, 11, {4}, 2, {10}, 5, {1}, {36}, 3, {87}, {60}, 1, {58}, 
  {3, 16}, 1, {56}, {75}, {14, 53}, 1, {30}, 1, {84}, 1, {59}, {35, 45, 68}}*)

Or in a more compact way using ReplaceAll:

Join @@ (SplitBy[l, Length] /. {{x : {} ..} :> {Length@{x}}})

(*{{12}, 4, {70}, 11, {4}, 2, {10}, 5, {1}, {36}, 3, {87}, {60}, 1, {58}, 
  {3, 16}, 1, {56}, {75}, {14, 53}, 1, {30}, 1, {84}, 1, {59}, {35, 45, 68}}*)
$\endgroup$

Your Answer

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

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