The lists I am working with consist of ordered sequences of natural numbers (except zero) and 'break markers'. The break markers are natural numbers in curly braces. They are called 'break markers' because they mark the end of a sub-sequence of entries.
Consider the list {1,2,{3},4,5}
as one example and also list {4,5,6,{7},{8},9}
as another one such instance. Note how the break markers can appear anywhere in the list including the beginning and end of the list. Note, also, how break markers can be consecutive entries in the list, as is shown in the later example above. Finally, note that the percentage of break markers in a list is expected to be relatively small eg around 20% of the list items are expected to be markers.
I am in search of an efficient, native, idiomatic way of achieving the output that is produced with the following piece of code:
proc[elem_]:=Module[{},
pouch = Flatten[{pouch, elem}];
If[
Not[IntegerQ[elem]],
bag = Flatten[{bag, {pouch}}, 1];
pouch = {};
]
]
partition[list_]:=Module[{comp},
Scan[proc[#]&, list];
comp = Complement[Flatten[list], Flatten[bag]];
If[
Length[comp] > 0,
bag = Flatten[{bag, {comp}}, 1]
];
]
(*here is the actual testing site*)
(
bag = {};
pouch = {};
partition[#];
{"breaks" -> Cases[#, {x_} :> x, 1], "output" -> bag}
) & /@ a list of problem instances
The issues I can identify with the code presented above are
- the presence of 'global' variables eg
bag
andpouch
- the fact that it is, in essence, a procedural code (inspect an element, then, if it satisfies the specified condition, collect it) written in a functional way (the
Scan[]
part of the code) - that the code fails to recognize the structure of the problem ie does not make use of the fact that the lists considered match patterns such as
{x__,{m_}}
,{{m_},x__}
,{{m_}}
or{x__}
.
Please note that I'm not sure if (2.) above is accurate or if it actually is an issue. Also note how I tried using Shortest[]
and Longest[]
with various assortments of the patterns in (3.) but didn't have much luck.
Any help (notes, comments, suggestions etc) is greatly appreciated.
The following code can be used to produce acceptable sequences for testing purposes:
YEARS = 57
RANGE = Range[YEARS]
PBR = 0.2
BREAKS = Ceiling[PBR YEARS]
BREAKSSUBSETS = {0, BREAKS}
CASES = 1
(
MARKERS = RandomSample[RANGE, #]
RANGE /. Thread[MARKERS -> Transpose[{MARKERS}]];
) & /@ RandomInteger[BREAKSSUBSETS, CASES]
Update no. 1: The code has been updated to return the desired output.
bag
andpouch
to empty lists. What should be the result if{4,5,6,{7},{8},9}
is the input? $\endgroup${4,5,6,{7},{8},9}
should be{{4,5,6,7},{8},{9}}
. My code does not produce this desired output for reasons I cannot address at this point. Will get back to it within the day. Thanks for the input! $\endgroup$Flatten /@ Split[{1, 2, {3}, 4, 5, 6, {7}, {8}, 9, 10, {11}, {12}}, ! ListQ[#1] &]
? $\endgroup$diff = Differences@({0}~Join~Flatten@Position[ListQ /@ list, True]); Flatten /@ Internal`PartitionRagged[list, diff]
. While J. M.'s solution is the simplest that comes to mind, I personally like solutions that show usage of different commands as they might have a didactic flavor with introducing a user to new (to him) possibilities. E.g., I didn't know aboutDifferences
a few weeks ago. $\endgroup$