从OrderedCollection中选择以下项目的最佳方式是什么:

时间:2012-08-05 14:46:39

标签: smalltalk pharo

给定像这样的OrderedCollection:

noise1
noise2
noise3
signal1
signal1
signal1
signal1
randomButInteresting
noise4
noise5

我想选择一个新的OrderedCollection所有对象“signal1”和该系列“signal1”之后出现的对象,“randomButInteresting”。 (每个Collection只会发生一次同一个信号。)

最优雅的方法是什么?

4 个答案:

答案 0 :(得分:5)

直接方法类似于

| 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)。更聪明的是找到信号组的边界,使用二进制搜索只发生一次

答案 1 :(得分:2)

您可以使用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)

答案 2 :(得分:2)

在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))

答案 3 :(得分:1)

使用输入和输出流的不同解决方案(是的,我喜欢流: - )):

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
    ]