2

Consider a simple PHP ArrayObject with two items.

$ao = new ArrayObject();
$ao[] = 'a1';  // [0] => a1
$ao[] = 'a2';  // [1] => a2

Then delete the last item and add a new item.

$ao->offsetUnset(1);
$ao[] = 'a3';  // [2] => a3

I'd very much like to be able to have 'a3' be [1].

How can I reset the internal pointer value before I add 'a3'?

I have a simple function that does this but I'd rather not copy the array if I don't have to.

function array_collapse($array) {
    $return = array();
    while ($a = current($array)) {
        $return[] = $a;
        next($array);
    }
    return $return;
}
allnightgrocery
  • 1,370
  • 1
  • 8
  • 15
  • It occurs to me that my example is only one of a couple use-case scenarios that I'm encountering. For the sake of the question, I'll leave it intact but also add... If the array element(s) to be removed are not the last element(s) then a collapse is necessary before resetting the internal pointer. Is it possible to have an array of four elements ([0], [1], [2], and [3]), remove [1] and [2], and reset the pointer so the next element to be added gets [2]? – allnightgrocery Sep 01 '10 at 22:35

3 Answers3

2

With the expansion on the question in your comments: you'd have to extend the ArrayObject class to get this kind of behavior:

class ReindexingArray extends ArrayObject {
    function offsetUnset($offset){
        parent::offsetUnset($offset);
        $this->exchangeArray(array_values($this->getArrayCopy()));
    }
    //repeat for every other function altering the values.
}

Another option would be the SplDoublyLinkedList:

<?php
$u = new SplDoublyLinkedList();
$array = array('1' => 'one',
               '2' => 'two',
               '3' => 'three');
foreach($array as $value) $u[] = $value;
var_dump($u);
unset($u[1]);        
var_dump($u);
$u[] = 'another thing';
var_dump($u);
Wrikken
  • 69,272
  • 8
  • 97
  • 136
  • Is this still the best answer today? I have the same issue and I'm worried about the performance impact of the line $this->exchangeArray(array_values(...)) – Flion Jun 25 '14 at 14:54
  • The best answer is to not care what number your keys are. Think about that first: why would you need what the OP needs? – Wrikken Jun 25 '14 at 14:59
  • well I had to loop over the members of the ArrayObject and delete some. To avoid this I went through the assumed keys from the highest to the lowest. But agreed: not needing to know the keys is the right solution, and I've already rewritten the code by using getArrayCopy() – Flion Jun 25 '14 at 19:27
0

Why not use offsetSet:

$ao = new ArrayObject();
$ao[] = 'a1';  // [0] => a1
$ao[] = 'a2';  // [1] => a2
$ao->offsetUnset(1);
$ao->offsetSet(1, 'a3');
smoak
  • 14,554
  • 6
  • 33
  • 33
0

This is kind of lame, but you can cast it to standard array and use array_splice on it:

$ao = new ArrayObject();
$ao[] = 'element 1';
$ao[] = 'element 2';
$ao[] = 'element 3';
$ao[] = 'element 4';

var_dump($ao);

$items = (array) $ao;
array_splice($items, 1, 2);
$ao = new ArrayObject($items);
$ao[] = 'element 5';

var_dump($ao);

This results in:

object(ArrayObject)#1 (1) {
  ["storage":"ArrayObject":private]=>
  array(4) {
    [0]=>
    string(9) "element 1"
    [1]=>
    string(9) "element 2"
    [2]=>
    string(9) "element 3"
    [3]=>
    string(9) "element 4"
  }
}
object(ArrayObject)#2 (1) {
  ["storage":"ArrayObject":private]=>
  array(3) {
    [0]=>
    string(9) "element 1"
    [1]=>
    string(9) "element 4"
    [2]=>
    string(9) "element 5"
  }
}
Matthew Purdon
  • 754
  • 11
  • 28