10
$\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
  • 1
    $\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
    Commented Feb 16, 2023 at 14:09
  • $\begingroup$ Sequence functions aren't going to be competitors @rhermans. $\endgroup$
    – Syed
    Commented Feb 16, 2023 at 14:11
  • $\begingroup$ @Syed let the race begin! 🏁 $\endgroup$
    – rhermans
    Commented Feb 16, 2023 at 14:16

6 Answers 6

14
$\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$
4
$\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$
2
$\begingroup$
list =
  {{12}, {}, {}, {}, {}, {70}, {}, {}, {}, {}, {}, {}, {}, {}, {}, 
  {}, {}, {4}, {}, {}, {10}, {}, {}, {}, {}, {}, {1}, {36}, {}, {}, 
  {}, {87}, {60}, {}, {58}, {3, 16}, {}, {56}, {75}, {14, 53}, {}, 
  {30}, {}, {84}, {}, {59}, {35, 45, 68}};

Using SequenceCases and First with its second argument

SequenceCases[list, {a_, b : {} ...} :> 
  Sequence[a, First[Values @ Counts[{b}], Nothing]]]

{{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$
1
$\begingroup$

Using:

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

then

If[Length[#[[1]]] == 0, Length@#, Flatten[#]] & /@ Split[l]

yields: {{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 you have read our privacy policy.

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