What is the most elegant way to select the following elements from an OrderedCollection:

To order an OrderCollection as follows:

noise1 noise2 noise3 signal1 signal1 signal1 signal1 randomButInteresting noise4 noise5 

I want to select for the new OrderedCollection all the objects "signal1" and the object that comes after this series of "signal1" s, "randomButInteresting". (A series of the same signal appears only once for each collection.)

What is the most elegant way to do this?

+4
source share
4 answers

Using the Lukas version with PetitParser, but saving the result "signal1" as a result:

 " the parser that accepts the symbol #signal1 " signal := PPPredicateObjectParser expect: #signal1. " the parser that accepts many symbols #signal1 followed by something else " pattern := signal plus , signal negate. data := #(noise1 noise2 noise3 signal1 signal1 signal1 signal1 randomButInteresting noise4 noise5). pattern flatten matchesSkipIn: data -> an OrderedCollection(#(#signal1 #signal1 #signal1 #signal1 #randomButInteresting)) 
+2
source

The direct method is something like

 | data result lastWasSignal | data := #( #noise1 #noise2 #noise3 #signal1 #signal1 #signal1 #signal1 #randomButInteresting #noise4 #noise5 ). lastWasSignal := false. result := data select: [ :value | | isElementAppropriate | isElementAppropriate := value = #signal1 or: [ lastWasSignal ]. lastWasSignal := value = #signal1. isElementAppropriate ]. result 

This is O (n). It would be smarter to find the boundaries of a group of signals that occurs only once using binary search.

+5
source

You can use PetitParser because you essentially match a specific pattern in the input stream. The parser definition with some comments added for clarity is as follows:

 " the parser that accepts the symbol #signal1 " signal := PPPredicateObjectParser expect: #signal1. " the parser that accepts the symbol #signal1 not followed by something else " pattern := signal , signal negate. " the parser that extract the second symbol " parser := pattern map: [ :signal :random | random ]. 

When you run this on your input, you will get:

 data := #(noise1 noise2 noise3 signal1 signal1 signal1 signal1 randomButInteresting noise4 noise5). parser matchesIn: data -> #(randomButInteresting) 
+2
source

Another solution using input and output streams (yes, I like streams :-)):

 data := #(noise1 noise2 noise3 signal1 signal1 signal1 signal1 randomButInteresting noise4 noise5). "Let create an OrderedCollection from an output stream" OrderedCollection streamContents: [:output | |datast| "We are basically streaming on the input data, so let use a stream:" datast := data readStream. "We ignore everything before #signal1" datast skipTo: #signal1. "We add the #signal1we just found" output nextPut: #signal1. "And we add all the subsequent #signal1" [datast peek = #signal1] whileTrue: [output nextPut: datast next]. "Finally we add the element after the last #signal1" output nextPut: datast next ] 
+1
source

All Articles