4
$\begingroup$

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

  1. the presence of 'global' variables eg bag and pouch
  2. 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)
  3. 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.

$\endgroup$
  • $\begingroup$ Your code doesn't seem to work; I only get an empty list when I set bag and pouch to empty lists. What should be the result if {4,5,6,{7},{8},9} is the input? $\endgroup$ – J. M.'s discontentment Oct 2 '16 at 8:10
  • $\begingroup$ @J.M. You were correct, I made some adjustments to the code. I'm sorry for that. The output for {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$ – user42582 Oct 2 '16 at 8:22
  • 5
    $\begingroup$ I see; how about something like Flatten /@ Split[{1, 2, {3}, 4, 5, 6, {7}, {8}, 9, 10, {11}, {12}}, ! ListQ[#1] &]? $\endgroup$ – J. M.'s discontentment Oct 2 '16 at 8:27
  • 1
    $\begingroup$ @J.M. - that's elegant... $\endgroup$ – ciao Oct 2 '16 at 8:44
  • $\begingroup$ Let me do: 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 about Differences a few weeks ago. $\endgroup$ – corey979 Oct 2 '16 at 10:26
4
$\begingroup$

Since the OP seems to be satisfied with the simple approach, I shall post it here:

l = {1, 2, {3}, 4, 5, 6, {7}, {8}, 9, 10, {11}, {12}};
Flatten /@ Split[l, ! ListQ[#] &]
   {{1, 2, 3}, {4, 5, 6, 7}, {8}, {9, 10, 11}, {12}}

Here is a variation of corey's suggestion in the comments:

pos = Prepend[Flatten[Position[l, _List, 1]], 0];
Inner[Flatten[Take[l, {#1, #2}]] &, Most[pos] + 1, Rest[pos], List]
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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