2015-01-16 3 views
4

Что такое идиоматический способ обнаружения последовательностей x раз одного и того же объекта (или объекта с определенным параметром соответствия) в OrderedCollection или Array?Идиоматический способ обнаружения последовательностей x раз один и тот же объект в массиве в Smalltalk?

E.g. содержит ли массив в 10 раз больше числа 5?

ответ

3

Получение последовательности повторяющихся объектов так же просто, как:

({ 1. 1. 2. 2. 2. 5. 5. 3. 9. 9. 9. 9. } as: RunArray) runs 
=> #(2 3 2 1 4) 

Если вы хотите, чтобы проверить, есть ли пробег, удовлетворяющий специфические ограничения, вы можете сделать что-то вроде следующего:

meetsConstraint := false. 
({ 1. 1. 2. 2. 2. 5. 5. 3. 9. 9. 9. 9. } as: RunArray) runsAndValuesDo: [:run :value | 
    meetsConstraint := (value = 9 and: [run > 3])]. 

Если вы хотите проверить определенное свойство объекта, а не объект равенства , вы можете легко создать RunArray этого свойства, сделав collect: на нем.

Так обобщенное решение будет выглядеть примерно так:

SequenceableCollection >> containsRunOf: anElement withAtLeast: nElements 
    (self as: RunArray) runsAndValuesDo: [:run :value | 
     (value = anElement and: [run >= nElements]) ifTrue: [^ true]]. 
    ^false 

А потом:

({ 'aa'. 'bb'. 'c'. 'ddd'. } collect: [:each | each size]) 
    containsRunOf: 2 withAtLeast: 3 
=> false 
+0

Ницца. Я бы предложил селектор '#contains: runningOf:', как в '# (2 1 1 1 2), содержит: 3 runOf: 1'. –

+1

@LeandroCaniglia Я еще не очень доволен именем. Однако 'contains: runsOf:' также не будет в точку, так как один «запуск» действительно относится ко всему блоку равных объектов. Поэтому 'runningOf:' будет подразумевать тестирование для нескольких запусков, в то время как мы фактически проверяем один пробег размера 'x'. Может быть, что-то лучше придет мне на ум ... – Leo

+0

Понял. Тогда я думаю, что буду придерживаться 'contains: n последовательныхTimes: anObject', как это было предложено в моем ответе. –

3

Я бы сказал, что вы должны следовать шаблону, как это:

(collectionToTest 
    indexOfSubCollection: (
    Array 
     new:  numberOfRepetitions 
     withAll: desiredObject) 
    startingAt: 1 
) isZero not 

Может быть, я не знаю, некоторые из полезных методов в Pharo, но если определить те, как:

SequenceableCollection >> indexOfSubCollection: aSubCollection 
^aSubCollection indexOfSubCollection: aSubCollection startingAt: 0 

SequenceableCollection >> containsSubCollection: aSubCollection 
^(aSubCollection indexOfSubCollection: aSubCollection) isZero not 

Object >> asArrayOf: aLength 
^Array new: aLength withAll: self 

то определение может быть уплощен в:

collectionToTest containsSubCollection: 
    (desiredObject asArrayOf: numberOfRepetitions) 

или для примера:

anArray containsSubCollection: (5 asArrayOf: 10) 

P.S. Я не уверен в именах методов. Может быть, inArrayOf: может быть лучше, чем asArrayOf: и так далее.

4

Мне нравится ответ Uko и хотел бы предложить другое решение, в котором будет рассмотрен раздел «соответствующий параметр» вашего вопроса. В SequenceableCollection определяют:

contains: m consecutiveElementsSatisfying: block 
    | n i | 
    self isEmpty ifTrue: [^m = 0]. 
    n := self size - m + 1. 
    i := 1. 
    [i <= n] whileTrue: [| j | 
     (block value: (self at: i)) ifTrue: [ 
      j := 2. 
      [j <= m and: [block value: (self at: i + j - 1)]] 
       whileTrue: [j := j + 1]. 
      j > m ifTrue: [^true]]. 
     i := i + 1]. 
    ^false 

Теперь, например, следующие два выражения будут оценивать истинного

#(2 1 1 1 2) contains: 3 consecutiveElementsSatisfying: [:e | e = 1] 
#(2 1 0 1 2) contains: 3 consecutiveElementsSatisfying: [:e | e squared = e] 

Примечание: Если вы хотите версию этого метода startingAt: n просто инициализировать i := n вместо i := 1 просто перед основным контуром.

EDIT:

И, конечно, мы можем завершить протокол со следующим методом в SequenceableCollection:

contains: m consecutiveTimes: anObject 
    ^self contains: m consecutiveElementsSatisfying: [:e | e = anObject] 

И пример:

#(2 1 1 1 2) contains: 3 consecutiveTimes: 1 
+0

Кук, спасибо. Один вопрос: почему вы начинаете считать 'j' (фактическое обнаруженное количество элементов в строке) с 2 вместо 1? – MartinW