给定这样的 OrderedCollection:
noise1
noise2
noise3
signal1
signal1
signal1
signal1
randomButInteresting
noise4
noise5
我想为新的 OrderedCollection 选择所有对象“signal1”以及这一系列“signal1”之后的对象,“randomButInteresting”。(一系列相同的信号在每个 Collection 中只出现一次。)
最优雅的方法是什么?
直接的方法类似于
| 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
是 O(n)。更聪明的方法是使用二分搜索找到仅出现一次的信号组的边界。
使用带有 PetitParser 的 Lukas 版本,但在结果中保留所有“signal1”:
" 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))
您可以使用PetitParser,因为您基本上匹配输入流上的特定模式。为清楚起见添加了一些注释的解析器定义如下:
" 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 ].
当您在输入数据上运行它时,您会得到:
data := #(noise1 noise2 noise3 signal1 signal1
signal1 signal1 randomButInteresting
noise4 noise5).
parser matchesIn: data -> #(randomButInteresting)
使用输入和输出流的不同解决方案(是的,我喜欢流:-)):
data := #(noise1 noise2 noise3 signal1 signal1 signal1 signal1 randomButInteresting noise4 noise5).
"Let's create an OrderedCollection from an output stream"
OrderedCollection streamContents: [:output |
|datast|
"We are basically streaming on the input data, so let's 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
]