Message Boards Message Boards

0
|
10665 Views
|
8 Replies
|
10 Total Likes
View groups...
Share
Share this post:

Need some help to make this rule work in Mathematica

Posted 11 years ago
Suppose I have this list:
lst = {db, st1, 3, 333.33, 4, 543, 11, 323, de, db, st2, 9, 987, 8, 778, de};

What matters here is that block structures begin with an item db, followed by an item and end with another item de
What I need to do here is convert the list to something like this:

 {
{st1,3, 333.33},
{st1,4, 543},
{st1,11, 323},
{st2,9, 987},
{st2,8, 778}
};

How would you write a rule to accomplish this?
I'm trying to stay away from procedural programming/

The biggest issue I'm struggling with is that the rule
{db, __, de} -> axa
matches the entire list and I can't tell Mathematica to look for the shortest such list
Shortest[] doesn't seem to be working for me either, perhaps I'm not using it properly

Any suggestions?

Thanks in advance!
POSTED BY: Todor Latev
8 Replies
Is your list always going to have an even number of entries after the st1, st2, ... entries and before the de?
Posted 11 years ago
My lame attempt emoticon
 In[1]:=lst = {db, st1, 3, 333.33, 4, 543, 11, 323, de, db, st2, 9, 987, 8, 778, de};
 
 In[2]:= step1 = Partition[SplitBy[lst, NumberQ] /. {__, x_?StringQ} -> x, 2]
 
 Out[2]= {{st1, {3, 333.33, 4, 543, 11, 323}}, {st2, {9, 987, 8, 778}}}
 
 In[3]:= step2 = Cases[step1, {x_, y_} -> Riffle[y, x, {1, -1, 3}]]
 
 Out[3]= {{st1, 3, 333.33, st1, 4, 543, st1, 11, 323, st1}, {st2, 9, 987, st2, 8, 778, st2}}

In[4]:= Flatten[Partition[#, 3] & /@ step2, 1]

Out[4]= {{st1, 3, 333.33}, {st1, 4, 543}, {st1, 11, 323}, {st2, 9, 987}, {st2, 8, 778}}
POSTED BY: Girish Arabale
This works and may be educational, but also ineffective for large lists (may be a bit over-spec, actually, depending on your input format):
lst //. {a___,
   Longest[PatternSequence[db, id_, nums : _?NumberQ .., de]],
   c___} :> {a, {id, #} & /@ Partition[{nums}, 2], c};
Flatten /@ Cases[%, {id_Symbol, {x_?NumericQ, y_?NumericQ}}, -1]
or
Reap[lst //. {a___,
      Longest[PatternSequence[db, id_, nums : _?NumberQ .., de]],
      c___} :> {a, Sow[Flatten[{id, #}]] & /@ Partition[{nums}, 2],
      c};][[2, 1]]

You should take care with using symbols as delimiter elements, this is prone to errors if any of these are assigned a value at some point. You should use strings like "db"  or protect those symbols you know you are going to use. BTW, answers to a very similar question can be found here.
POSTED BY: Yves Klett
All current solution look very long and complicated, here is mine:
GroupOut[x_, y_] := {x, #} & /@ y
lst = lst //. {y___, db, a_, Shortest[x__], de, z___} :> {y, {a, {x}},z}
lst = Flatten[GroupOut @@@ lst, 1]
One replace, one to `flatten'.

regards.
POSTED BY: Sander Huisman
Hi everybody

There is a faster and more concice method. I first do it step by step.

1) Split before every occurence of "db" :
Split[lst, #2 =!= db &]
{{db, st1, 3, 333.33, 4, 543, 11, 323, de}, {db, st2, 9, 987, 8, 778,
  de}}
2) Remove the "db" and "de" in each sublists :
#[[2 ;; -2]] & /@ %
{{st1, 3, 333.33, 4, 543, 11, 323}, {st2, 9, 987, 8, 778}}
3) Rearrange each sublists :
% /. {s_Symbol,
   n__?NumericQ} :> (Prepend[#, s] & /@ Partition[{n}, 2])
{{{st1, 3, 333.33}, {st1, 4, 543}, {st1, 11, 323}}, {{st2, 9,
   987}, {st2, 8, 778}}}
4) Flatten at level 1 for the result
Flatten[%, 1]
{{st1, 3, 333.33}, {st1, 4, 543}, {st1, 11, 323}, {st2, 9, 987}, {st2,
   8, 778}}


All in one :
Flatten[(#[[2 ;; -2]] & /@ Split[lst, #2 =!= db &]) /. {s_Symbol,
    n__?NumericQ} :> (Prepend[#, s] & /@ Partition[{n}, 2]), 1]
Regards
Posted 11 years ago
Here's my approach:
lst = {db, st1, 3, 333.33, 4, 543, 11, 323, de, db, st2, 9, 987, 8, 778, de};

Partition[
Join @@ (Prepend[Riffle[#[[3 ;; -2]], #[[2]], 3], #[[2]]] & /@
    Split[lst, # =!= de &]), 3]
POSTED BY: Markus Schopfer
Since you asked for a rule, this one does what you want; notice //. is ReplaceRepeated. Also, notice use of Sequence to inject the finished structure back into the result with the edge items removed. The first tripple underscore a___ BlankNullSequence accounts for the first block item being at the front edge of the List. The last BlankNullSequence represents all the unprocessed blocks and handles the last block item being at the end of the List. When using ReplaceRepeated, it is important that the result be transformed in some way.
lst //. {a___, db, b_, c__, de, d___} :> {a, Sequence @@ (Flatten /@ Thread[{b, Partition[{c}, 2]}]), d}
Posted 11 years ago
Many thanks to everyone for all the input - I didn't expect so many replies in such a short timeframe.
I need to take some time now to carefully study all the suggested solutions - it's all very valuable info, like a textbook
Special thanks goes to Christopher French in particular for his elegant rule based solution - that's exactly what I was looking for!
Any recommended learning resources for rule based programming in MA?
Solutions to particular problems such as this one would be most helpful
POSTED BY: Todor Latev
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract