0
|
11286 Views
|
8 Replies
|
10 Total Likes
View groups...
Share
GROUPS:

# 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 deWhat 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} -> axamatches 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 properlyAny suggestions?Thanks in advance!
8 Replies
Sort By:
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 textbookSpecial 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 11 years ago
 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
 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 11 years ago
 Hi everybodyThere 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 resultFlatten[%, 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
 All current solution look very long and complicated, here is mine:GroupOut[x_, y_] := {x, #} & /@ ylst = lst //. {y___, db, a_, Shortest[x__], de, z___} :> {y, {a, {x}},z}lst = Flatten[GroupOut @@@ lst, 1]One replace, one to `flatten'.regards.
Posted 11 years ago
 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 11 years ago
 My lame attempt  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 11 years ago
 Is your list always going to have an even number of entries after the st1, st2, ... entries and before the de?