鉴于两个集合:
srcCollection := #('Lorem' 'ipsum' 'dolor' 'sit' 'amet,' 'consectetur' 'adipisicing' 'elit,' 'sed' 'do' 'eiusmod' 'tempor' 'incididunt' 'ut' 'labore' 'et' 'dolore' 'magna' 'aliqua.' 'Ut' 'enim' 'ad' 'minim' 'veniam,' 'quis' 'nostrud' 'exercitation' 'ullamco' 'laboris' 'nisi' 'ut' 'aliquip' 'ex' 'ea' 'commodo' 'consequat.' 'Duis' 'aute' 'irure' 'dolor' 'in' 'reprehenderit' 'in' 'voluptate' 'velit' 'esse' 'cillum' 'dolore' 'eu' 'fugiat' 'nulla' 'pariatur.' 'Excepteur' 'sint' 'occaecat' 'cupidatat' 'non' 'proident,' 'sunt' 'in' 'culpa' 'qui' 'officia' 'deserunt' 'mollit' 'anim' 'id' 'est' 'laborum').
objCollection := #('Lorem' 'numquam' 'eius' 'modi' 'tempora' 'incidunt' 'ut' 'labore' 'et' 'dolore' 'magnam' 'aliquam' 'ipsum' 'dolor' 'ex' 'ea' 'commodo' 'consequat.' 'Duis' 'aute' 'irure' 'dolor' 'in' 'reprehenderit' 'in' 'voluptate' 'velit' 'esse' 'cillum' 'dolore' 'eu' 'fugiat' 'nulla' 'pariatur.' 'Excepteur' 'sint' 'occaecat' 'cupidatat' 'non' 'proident,' 'sunt' 'in' 'culpa' 'qui' 'officia' 'deserunt' 'mollit' 'anim' 'id' 'est' 'laborum' 'Sed' 'ut' 'perspiciatis' 'unde' 'omnis' 'iste' 'natus' 'error' 'sit' 'voluptatem' 'accusantium' 'doloremque' 'laudantium,' 'totam' 'rem' 'aperiam,' 'eaque' 'ipsa' 'quae' 'ab' 'illo' 'inventore' 'veritatis' 'et' 'quasi' 'architecto' 'sit' 'amet,' 'consectetur' 'adipisicing' 'elit,' 'sed' 'do' 'eiusmod' 'tempor' 'incididunt' 'ut' 'labore' 'et' 'dolore' 'magna' 'aliqua.' 'Ut' 'enim' 'ad' 'minim' 'veniam,' 'quis' 'nostrud' 'exercitation' 'ullamco' 'laboris' 'nisi' 'ut' 'aliquip' 'beatae' 'vitae' 'dicta' 'sunt' 'explicabo.' 'Nemo' 'enim' 'ipsam' 'voluptatem' 'quia' 'voluptas' 'sit' 'aspernatur' 'aut' 'odit' 'aut' 'fugit,' 'sed' 'quia' 'consequuntur' 'magni' 'dolores' 'eos' 'qui' 'ratione' 'voluptatem' 'sequi' 'nesciunt.' 'Neque' 'porro' 'quisquam' 'est,' 'qui' 'dolorem' 'ipsum' 'quia' 'dolor' 'sit' 'amet,' 'consectetur,' 'adipisci' 'velit,' 'sed' 'quia' 'non' 'quaerat' 'voluptatem.' 'Ut' 'enim' 'ad' 'minima' 'veniam,' 'quis' 'nostrum' 'exercitationem' 'ullam' 'corporis' 'suscipit' 'laboriosam,' 'nisi' 'ut' 'aliquid' 'ex' 'ea' 'commodi' 'consequatur?' 'Quis' 'autem' 'vel' 'eum' 'iure' 'reprehenderit' 'qui' 'in' 'ea' 'voluptate' 'velit' 'esse' 'quam' 'nihil' 'molestiae' 'consequatur,' 'vel' 'illum' 'qui' 'dolorem' 'eum' 'fugiat' 'quo' 'voluptas' 'nulla' 'pariatur?').
其中objCollection保证包含srcCollection中的所有元素。注意:在我的应用程序中,objCollection实际上是包含这些字符串作为标识符而没有重复项的复杂对象。
我一直在测量并尝试优化选择objCollection中同样位于srcCollection中的所有对象。使用带有堆栈VM的Pharo 1.2中的[ 1000 timesRepeat: [ ... ] ] timeToRun
和带有2Gb内存的Windows XP时,以下时间是以毫秒为单位。这些是我的尝试:
objCollection intersection: srcCollection
7537
7507
objCollection select: [: str | srcCollection includes: str ]
7471
7507
srcCollection collect: [: str | objCollection detect: [: obj | obj = str ] ]
4227
4323
有更快的方法吗?
答案 0 :(得分:4)
前两个做同样的事情:Collection >> #intersection:
的实现是self select: [:each | aCollection includes: each]
。
Collection >> #intersection:
最终使用self anySatisfy: [:x | x = mySearchObj ]
来完成其工作,该工作使用#do:
遍历集合。 #detect:
最终会做同样的事情。
我怀疑你看到的差异不是因为三者中的任何一个都比另一个更有效,而是垃圾收集之类的产品。
鉴于此,我选择#intersection:
因为它的语义清晰。它说的是你想要的,而不是其他两个,你只看到你如何得到你想要的东西,并且必须推断/推断出意图。
答案 1 :(得分:1)
如果您能够将asSet
添加到这两个集合中,您可能会做得更快。我从1480年到197年。
答案 2 :(得分:0)
两个集合都有重复。
srcCollection size ~= srcCollection asSet size.
objCollection size ~= objCollection asSet size.
如果您想处理重复项,假设您通过<另一种可能性是使用这种方法(成本n1 * log(n1)+ n2 * log(n2)+ n1 + n2而不是n1 * n2用于天真交叉)
Collection>>sortedIntersection: aCollection
"Answer the intersection of two collections, sorted by < and accounting duplicates."
| intersection obj objStream src srcStream |
srcStream := self sorted readStream.
objStream := aCollection sorted readStream.
intersection := (Array new: self size) writeStream.
[srcStream atEnd | objStream atEnd] whileFalse:
[src := srcStream next.
obj := objStream next.
[src = obj] whileFalse:
[[src < obj] whileTrue: [srcStream atEnd ifTrue: [^intersection contents]. src := srcStream next].
[obj < src] whileTrue: [objStream atEnd ifTrue: [^intersection contents]. obj := objStream next]].
intersection nextPut: src].
^intersection contents
这也可以使用Heap,并删除第一个元素,但速度很慢。
heapSortedIntersection: aCollection
"Answer the intersection of two collections, sorted by < and accounting duplicates."
| intersection obj src objHeap srcHeap |
srcHeap := Heap withAll: self.
objHeap := Heap withAll: aCollection.
intersection := (Array new: self size) writeStream.
[srcHeap isEmpty | objHeap isEmpty] whileFalse:
[src := srcHeap removeFirst.
obj := objHeap removeFirst.
[src = obj] whileFalse:
[[src < obj] whileTrue: [srcHeap isEmpty ifTrue: [^intersection contents]. src := srcHeap removeFirst].
[obj < src] whileTrue: [objHeap isEmpty ifTrue: [^intersection contents]. obj := objHeap removeFirst]].
intersection nextPut: src].
^intersection contents
最后,如果您没有可用的总订单,您可以简单地使用Bag,仍然考虑重复
bagIntersection: aCollection
"Answer the intersection of two collections, accounting duplicates."
| objBag absentTag |
objBag := Bag withAll: aCollection.
absentTag := Object new.
^self reject: [:each | (objBag remove: each ifAbsent: [absentTag]) == absentTag]