Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Suppose I have a list of arbitrary length like

{1, 2, 3, "Open", 3, 2, "Close", 9, 3, 4, "Open", 1, 0, "Close", 3, 5}

and I am trying to extract the sequences inside the open/close tags, i.e. the answer I want is

{{3, 2}, {1, 0}}

What's the right way to do this? The data I am actually working is a large XML document and I am trying to extract sections of it by identifying certain tags as boundaries. I've fiddled with different pattern matching functions but can't figure out how to operate on a list in this way since I am trying to match patterns on an intermediate level between individual elements and the entire list.

EDIT

To clarify, I don't know in advance how many such sequences the data will contain or how many elements will be inside any particular set of tags.

share|improve this question
1  
ugly: Take[list, #] & /@ (Partition[ Flatten[Position[list, "Open" | "Close"]], 2] /. {a_?NumberQ, b_?NumberQ} -> {a + 1, b - 1}) –  chuy Apr 30 '13 at 20:37
add comment

4 Answers

up vote 5 down vote accepted

Try this one

ReplaceList[expr, {__, PatternSequence["Open",v__ /; Count[{v}, _String] == 0, 
            _String], __} -> {v}]
share|improve this answer
    
If you don't Flatten the data from the xml Case will be a good alternative. –  Spawn1701D Apr 30 '13 at 20:51
    
Good call on ReplaceList –  mfvonh Apr 30 '13 at 20:53
    
Maybe change PatternSequence["Open", v__ /; Count[{v}, _?(# == "Close" &)] == 0, "Close"] in case the list contains other strings than "Open"|"Close". –  b.gatessucks Apr 30 '13 at 21:02
    
@b.gatessucks yes the correct structure of the pattern will depend on the actual data, if the tags contain also in the data strings the OP should exclude just the xml tags. My opinion is that the XMLObject and XMLElement objects must be exploited instead of a flattened list. –  Spawn1701D Apr 30 '13 at 21:09
add comment

Here's a plain pattern approach, I'm not quite sure how robust it is:

ReplaceList[expr, {___, "Open", x : Except["Close"] ..., "Close", ___} :> {x}]

Also take a look at Longest and Shortest, which may come in handy.

share|improve this answer
add comment

My humble attempt:

list = {1, 2, 3, "Open", 3, 2, "Close", 9, 3, 4, "Open", 1, 0, 
   "Close", 3, 5};
SplitBy[
 Select[list, 
  (open = # != "Close" && (# == "Open" || open)) &], # == "Open" &] 
    //. "Open" | {} -> Sequence[]
share|improve this answer
add comment

I feel this is way too complicated, but anyway:

l = {1, 2, 3, "Open", 3, 4, 5, 2, "Close", 9, 3, 4, "Open", 0, 
   "Close", "Close", 3, 5};

Reap[l //. {a___, 
     PatternSequence["Open", mid : _?NumericQ .., "Close"], 
     b___} :> {a, Sow[{mid}]; mid, b}][[2, 1]]

{{3, 4, 5, 2}, {0}}

This example might have some limited instructional value showing one convoluted possible use of Sow and Reap.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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