Tuesday, May 3, 2011

PHP - Delete Item from Hash Table (array) using array_filter

Hi

In PHP, I know there is no official way to delete items once they have been put into an array. But there must be a "best-method" solution to my problem. I believe this may lie in the array_filter function.

Essentially, I have a shopping cart object that stores items in a hashtable. Imagine you can only ever buy one of any item at a time.

I do

add_item(1);
add_item(2);
remove_item(1);

get_count() still returns 2.

var $items;


function add_item($id) {
 $this->items[$id] = new myitem($id);
}

function remove_item($id) {
 if ($this->items[$id]) {
  $this->items[$id] = false;
  return true;
 } else { 
  return false;
 }
}


function get_count() {
 return count($this->items);
}

What do people think is the best method to use in get_count? I can't figure out the best way to use array_filter that simply doesn't return false values (without writing a seperate callback).

Thanks :)

From stackoverflow
  • if ($this->items[$id]) {
    

    May return a warning, should use array_key_exists or isset.

    unset() seems cleaner than assigning false when removing an item (will also get rid of your count problem).

  • No official way? Sure there is! Unset!

    <?php
    
    class foo
    {
        var $items = array();
    
    
        function add_item($id) {
                $this->items[$id] = new myitem($id);
        }
    
        function remove_item($id)
        {
            unset( $this->items[$id] );
    
        }
    
    
        function get_count() {
                return count($this->items);
        }
    }
    
    class myitem
    {
        function myitem( $id )
        {
         // nothing
        }
    }
    
    $f = new foo();
    
    $f->add_item( 1 );
    $f->add_item( 2 );
    
    $f->remove_item( 1 );
    
    echo $f->get_count();
    

    Also, is this PHP4? Because if not, you should look into some of the SPL stuff like ArrayObject or at least the the Countable and ArrayAccess interfaces.

    EDIT

    Here's a version using the interfaces directly

    <?php
    
    class foo implements ArrayAccess, Countable
    {
        protected $items = array();
    
        public function offsetExists( $offset )
        {
         return isset( $this->items );
        }
    
        public function offsetGet( $offset )
        {
         return $this->items[$offset];
        }
    
        public function offsetSet( $offset, $value )
        {
         $this->items[$offset] = $value;
        }
    
        public function offsetUnset( $offset )
        {
         unset( $this->items[$offset] );
        }
    
        public function count()
        {
         return count( $this->items );
        }
    
        public function addItem( $id )
        {
         $this[$id] = new myitem( $id );
        }
    }
    
    class myitem
    {
        public function __construct( $id )
        {
         // nothing
        }
    }
    
    $f = new foo();
    
    $f->addItem( 1 );
    $f->addItem( 2 );
    unset( $f[1] );
    
    echo count( $f );
    

    And here's a version as an implementation of ArrayObject

    <?php
    
    class foo extends ArrayObject
    {
        public function addItem( $id )
        {
         $this[$id] = new myitem( $id );
        }
    }
    
    class myitem
    {
        public function __construct( $id )
        {
         // nothing
        }
    }
    
    $f = new foo();
    
    $f->addItem( 1 );
    $f->addItem( 2 );
    unset( $f[1] );
    
    echo count( $f );
    
    Mario : Get rid of the isset condition ;)
    Peter Bailey : Oh, I guess it's not needed. I didn't test the code, but I guess it doesn't throw a warning with unset() after all.
  • +1 to both Peter's and Mario's answers: using unset() is the correct way to remove items from an array.

    I just wanted to leave a note to explain why your method wasn't working. Using count() will count the number of values in an array. false, though you could imagine it as meaning "nothing", is still actually a value. Typically if you want to actually specify "no value" then use null.

    You can also unset an array element by setting it to null, though look at the code below to see the difference.

    $x = array("a", "b", "c");
    
    var_dump(isset($x[0]));   // bool(true)
    var_dump(isset($x[1]));   // bool(true)
    var_dump(isset($x[2]));   // bool(true)
    echo count($x);           // 3
    
    $x[2] = null;
    var_dump(isset($x[2]));   // bool(false) -- the value is not set any longer
    echo count($x);           // 3  -- but it doesn't remove it from the array
    
    unset($x[1]);
    var_dump(isset($x[1]));   // bool(false)
    echo count($x);           // 2
    

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.