Optimization 使用Smalltalk中的其他集合选择对象的最快方法

Optimization 使用Smalltalk中的其他集合选择对象的最快方法,optimization,collections,smalltalk,Optimization,Collections,Smalltalk,给定两个集合: 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' 'exercit

给定两个集合:

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实际上是包含这些字符串作为标识符的复杂对象,没有重复项

srcCollection size ~= srcCollection asSet size.
objCollection size ~= objCollection asSet size.
我一直在测量并尝试优化选择objCollection中也在srcCollection中的所有对象。使用Pharo 1.2中的[1000 timesRepeat:[…]]timeToRun,使用堆栈VM和内存为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

有更快的方法吗?

前两种方法做相同的事情:集合>>交叉点:[每个集合包括:每个]的实现是自选择的

集合>>交集:最终使用self-anysuccess:[:x | x=mySearchObj]执行其工作,该工作使用do:在集合中进行迭代。检测:最终做同样的事情

我怀疑你看到的差异并不是因为三者中的任何一个都比另一个更有效率,而是垃圾收集之类的东西的产物


鉴于此,我会选择交集:因为它的语义清晰。它说的是你想要什么,而不是另外两个,在这两个集合中,你只能看到你如何得到你想要的,并且必须推断/推断意图。

如果你能负担得起向这两个集合添加资产,你可能会做得更快。我从1480到197毫秒。两个系列都有重复的

srcCollection size ~= srcCollection asSet size.
objCollection size ~= objCollection asSet size.
如果您想处理重复项,假设您有一个总订单,通过<另一种可能性是使用此方法成本n1*logn1+n2*logn2+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

谢谢你的提示,但是我忘了提到我的数据集不包含重复项,如果你是指用于删除重复项的资产。不,一个数据集使用不同的数据结构,速度更快。只需在objCollection和srcCollection定义的末尾添加asSet,只有示例中的srcCollection需要是一个集合,这样才能快速完成。集合有01 includes:实现,而这两个集合在迭代器上都有:
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]