【问题标题】:Reorganizing the children of an SplObjectStorage instance重新组织 SplObjectStorage 实例的子代
【发布时间】:2012-01-04 18:11:59
【问题描述】:

我有一个 SplObjectStorage 实例,它存储要在容器中呈现的元素对象。我希望能够有效地从商店中的任何随机位置添加和删除对象。

例子:

<?php
$store = new SplObjectStorageWrapper;
$obj1 = new Obj;
$obj2 = new Obj;
$obj3 = new Obj;

$store->attach($obj1);
$store->attach($obj2);
$store->insertAtIndex($obj3, 1);

//Storage should now be organized as $obj1, $obj3, $obj2

我将如何实现insertAtIndex 方法?我是否使用LimitIterator 在某个位置后分离和重新连接孩子?使用基于数组的对象存储已被证明比SplObjectStorage 实例慢得多。

我想实现的其他方法包括removeAtIndex(integer)indexOf(object)

【问题讨论】:

  • 你需要SplObjectStorage的Set部分吗,例如没有重复?如果没有,请尝试使用 SplPriorityQueue 类。它与insertAt 的工作方式不完全相同,但它可能对您的用例来说已经足够了。
  • 戈登,不是真的。但是由于性能上的巨大差异,我 /do/ 需要使用 SplObjectStorage 而不是基于数组的解决方案。

标签: php spl


【解决方案1】:

事实证明,最简单(显然也是最有效)的方法是扩展SplObjectStorage 并利用LimitIterator。下面的代码示例:

<?php
/**
 * Extends the SplObjectStorage class to provide index functions
 */
class ObjectStorage extends SplObjectStorage {

    /**
     * Returns the index of a given object, or false if not found
     * @param object $object
     */
    function indexOf($object){

        if(!$this->contains($object)) return false;

        foreach($this as $index => $obj) if($obj === $object) return $index;

    }

    /**
     * Returns the object at the given index
     */
    function itemAtIndex($index){

        $it = new LimitIterator($this, $index, 1);
        foreach($it as $obj) return $obj;

    }

    /**
     * Returns the sequence of objects as specified by the offset and length
     * @param int $offset
     * @param int $length
     */
    function slice($offset, $length){

        $out = array();
        $it = new LimitIterator($this, $offset, $length);
        foreach($it as $obj) $out[] = $obj;
        return $out;

    }

    /**
     * Inserts an object (or an array of objects) at a certain point
     * @param mixed $object A single object or an array of objects
     * @param integer $index
     */
    function insertAt($object, $index){

        if(!is_array($object)) $object = array($object);

        //Check to ensure that objects don't already exist in the collection
        foreach($object as $k => $obj):
            if($this->contains($obj)) unset($object[$k]);
        endforeach;

        //Do we have any objects left?
        if(!$object) return;

        //Detach any objects at or past this index
        $remaining = array();
        if($index < $this->count()):
            $remaining = $this->slice($index, $this->count() - $index);
            foreach($remaining as $obj) $this->detach($obj);
        endif;

        //Add the new objects we're splicing in
        foreach($object as $obj) $this->attach($obj);

        //Attach the objects we previously detached
        foreach($remaining as $obj) $this->attach($obj);

    }

    /**
     * Removes the object at the given index
     * @param integer $index
     */
    function removeAt($index){

        $this->detach($this->itemAtIndex($index));

    }

}

【讨论】:

    猜你喜欢
    • 2013-06-26
    • 2012-12-30
    • 2020-01-11
    • 2020-10-30
    • 2014-07-18
    • 2013-09-28
    • 2014-06-20
    • 1970-01-01
    • 2015-10-31
    相关资源
    最近更新 更多