在 Smalltalk 的数组中检测 x 次相同对象序列的惯用方法?
Idiomatic way to detect sequences of x times same object in an Array in Smalltalk?
在 OrderedCollection 或 Array 中检测 x 次相同对象(或具有特定匹配参数的对象)的序列的惯用方法是什么?
例如数组是否连续包含数字 5 的 10 倍?
我会说你必须遵循这样的模式:
(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:
等更好。
我喜欢 Uko 的回答,并想提供一个不同的解决方案来解决您问题的 "matching parameter" 部分。在 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
。
编辑:
当然,我们可以在SequenceableCollection
中用下面的方法完成协议:
contains: m consecutiveTimes: anObject
^self contains: m consecutiveElementsSatisfying: [:e | e = anObject]
以及示例:
#(2 1 1 1 2) contains: 3 consecutiveTimes: 1
获取重复对象的序列非常简单:
({ 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])].
如果您想测试某个对象的某个 属性 而不是对象是否相等,您可以通过 [=15= 轻松创建此 属性 的 RunArray
] 就可以了。
所以通用的解决方案看起来像这样:
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
在 OrderedCollection 或 Array 中检测 x 次相同对象(或具有特定匹配参数的对象)的序列的惯用方法是什么?
例如数组是否连续包含数字 5 的 10 倍?
我会说你必须遵循这样的模式:
(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:
等更好。
我喜欢 Uko 的回答,并想提供一个不同的解决方案来解决您问题的 "matching parameter" 部分。在 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
。
编辑:
当然,我们可以在SequenceableCollection
中用下面的方法完成协议:
contains: m consecutiveTimes: anObject
^self contains: m consecutiveElementsSatisfying: [:e | e = anObject]
以及示例:
#(2 1 1 1 2) contains: 3 consecutiveTimes: 1
获取重复对象的序列非常简单:
({ 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])].
如果您想测试某个对象的某个 属性 而不是对象是否相等,您可以通过 [=15= 轻松创建此 属性 的 RunArray
] 就可以了。
所以通用的解决方案看起来像这样:
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