Вставить элементы в позицию массива, даже если массив пуст или позиция не существует

Я пытался использовать array_splice стратегия, как описано здесь
Вставить новый элемент в массив в любой позиции в PHP

Но это не работает, так как массив пуст или ключ не существует. Поэтому я попытался проверить, установлен ли ключ первым, а затем создать его. Но все равно это не работает.

Если, например, массив пуст при первом вызове, и я хочу вставить элементы с индексом 3, и я создаю позицию 3 перед array_spliceэлементы вставляются из позиции 0. То же самое происходит, если я не проверяю перед использованием array_splice, Если массив пуст, вставка не удалась

function array_insert($array,$input,$index){
if(!isset($array[$index])) $array[$index] = 0;
array_splice($array,$index,0,$input);

return $array;
}

Итак, следующий звонок

array_insert(array(),array(36,37),3);

Создает это

array(1) { [3]=> int(0) } //var_dump before splice, after isset
array(3) { [0]=> int(0) [1]=> string(2) "36" [2]=> string(2) "37" } //var_dump  after splice

Что мне не хватает ?!

@редактировать
Ожидаемый результат:
Если я вставлю массив (‘a’, ‘b’, ‘c’) в позицию 3 в пустом массиве, результирующий массив должен позволить мне получить доступ к ‘a’ с помощью ключа 3, ‘b’ к 4 и т. Д. Не уверен, что лучше пустые, чтобы заполнить пробелы или ассоциативные ключи.

@ edit2

insert(array(),array(1,2),3);

array (2) {[3] => int (1) [4] => int (2)}

$a = array();
$a[2] = 3;
insert($a,array(1,2),1);

массив (3) { 1=> int (1) [2] => int (2) [3] => int (3)}

insert(array(1,2),array(4,5),1);

array (4) {[0] => int (1) 1=> int (4) [2] => int (5) [3] => int (2)}

Что касается производительности, что является лучшим выбором между прочим?

-1

Решение

Я думаю, что это удовлетворяет вашим требованиям, и я включил контрольные примеры, чтобы вы могли судить сами.

class ShiftingArray implements ArrayAccess
{
private $values;

public function __construct ($initial_values = array ())
{
$this->values = $initial_values;
}

public function get_values ()
{
return $this->values;
}

public function insert ($new_values, $offset)
{
if (!is_array ($new_values))
{
$new_values = array ($new_values);
}

foreach ($new_values as $value)
{
$this->insert_single ($offset, $value);
$offset++;
}
}

private function insert_single ($index, $value)
{
if (isset ($this->values[$index]))
{
$this->insert_single ($index + 1, $this->values[$index]);
}
$this->values[$index] = $value;
}

/**
*   The following methods allow you to use an instance of ShiftingArray
*   like a normal array, e.g.
*
*   $array = new ShiftingArray ();
*   $array->insert (array (1,2,3), 4);
*   echo $array[5]; //  prints 2
*/

/*  boolean ArrayAccess::offsetExists (mixed $offset) */
public function offsetExists ($offset)
{
return isset ($this->values [$offset]);
}

/*  mixed ArrayAccess::offsetGet (mixed $offset) */
public function offsetGet ($offset)
{
return isset ($this->values [$offset]) ? $this->values[$offset] : null;
}

/*  ArrayAccess::offsetSet (mixed $offset, mixed $value) */
public function offsetSet ($offset, $value)
{
$this->insert_single ($offset, $value);
}

/*  ArrayAccess::offsetUnset (mixed $offset) */
public function offsetUnset ($offset)
{
unset ($this->values[$offset]);
}
}

// begin test cases
$test_cases = array (
array (
'Name' => 'Start Empty, Zero Offset, Single Insert',
'Initial' => array (),
'Insert' => 6,
'Offset' => 0,
'Output' => array (0 => 6),
),
array (
'Name' => 'Start Empty, Zero Offset',
'Initial' => array (),
'Insert' => array (3, 2),
'Offset' => 0,
'Output' => array (0 => 3, 1 => 2),
),
array (
'Name' => 'Start Empty, Positive Offset, Single Insert',
'Initial' => array (),
'Insert' => 'hello',
'Offset' => 11,
'Output' => array (11 => 'hello'),
),
array (
'Name' => 'Start Empty, Positive Offset',
'Initial' => array (),
'Insert' => array (9, 'blah'),
'Offset' => 3,
'Output' => array (3 => 9, 4 => 'blah'),
),
array (
'Name' => 'No Shift',
'Initial' => array (1 => 9),
'Insert' => array (4, 'blah'),
'Offset' => 3,
'Output' => array (1 => 9, 3 => 4, 4 => 'blah'),
),
array (
'Name' => 'Single Shift',
'Initial' => array (2 => 13),
'Insert' => 6,
'Offset' => 2,
'Output' => array (2 => 6, 3 => 13),
),
array (
'Name' => 'Single Element, Double Shift',
'Initial' => array (2 => 13),
'Insert' => array (6, 7),
'Offset' => 2,
'Output' => array (2 => 6, 3 => 7, 4 => 13),
),
array (
'Name' => 'Multiple Element, Double Shift',
'Initial' => array (5 => 13, 6 => 15),
'Insert' => array (2, 3),
'Offset' => 5,
'Output' => array (5 => 2, 6 => 3, 7 => 13, 8 => 15),
),
array (
'Name' => 'Shift Only Some',
'Initial' => array (2 => 1, 5 => 13, 6 => 15),
'Insert' => array (2, 3),
'Offset' => 5,
'Output' => array (2 => 1, 5 => 2, 6 => 3, 7 => 13, 8 => 15),
),
array (
'Name' => 'Shift Fills Gaps',
'Initial' => array (2 => 0, 3 => 11, 6 => 9, 7 => 'a'),
'Insert' => array (12, 14),
'Offset' => 4,
'Output' => array (2 => 0, 3 => 11, 4 => 12, 5 => 14, 6 => 9, 7 => 'a'),
),
);

// run tests
$passes = $failures = 0;
foreach ($test_cases as $case)
{
$array = new ShiftingArray ($case['Initial']);
$array->insert ($case['Insert'], $case['Offset']);
if ($array->get_values () != $case['Output'])
{
echo $case['Name'] . " FAILED\n";
print_r ($array->get_values ());
print_r ($case['Output']);
echo "\n\n";
$failures++;
}
else
{
$passes++;
}
}
echo "\n\nTests Finished: $passes Passes, $failures Failures";
2

Другие решения

Через некоторое время мне и другу удалось заставить его работать. Я уверен, что это будет полезно для многих

function array_max_key($a){
if(count($a)) return max(array_keys($a));
return 0;
}

function array_insert($a,$b,$index){
if(!is_array($b)) $b = array($b);

$max = array_max_key($a);
if($index > $max) $max = $index;
$ab = array();
$max++;

for($i=0;$i<$max;$i++){
if(isset($a[$i]) && $i<$index){
$ab[$i] = $a[$i];
}else if($i == $index){
$_max = count($b);
for($j=0;$j<$_max;$j++){
$ab[$i+$j] = $b[$j];
}
if(isset($a[$i])) $ab[] = $a[$i];
}else if(isset($a[$i])){
if(isset($ab[$i])) $ab[] = $a[$i];
else $ab[$i] = $a[$i];
}
}

return $ab;
}

array_insert(array(),array(1,2,3),4);
$a = array(); $a[5] = 1; $a[6] = 2;
array_insert($a,2,4);

Поэтому, если вы попытаетесь добавить элементы в позицию I массива, он добавит их, даже если эта позиция не существует (или массив пуст), и сместит другие элементы, когда обнаружит конфликты. Элемент может быть либо массивом, либо нет

1

Вы так много говорили о сплайсинге, что я решил не писать свой вариант. Но это не абсолют 🙂

function array_insert($array, $add, $index) {
// make array with desired keys
$add = array_combine(range($index, $index + count($add)-1), $add);
// split old array to two parts - (0 <= key < $index) and ($index <= key)
$after = $index ? array_diff_key($array, array_flip(range(0, $index-1))) : $array;
$before = array_diff($array, $after);
// Combine arrays
$array = array_replace($add, $before);
foreach($after as $item)
$array[] = $item;
return($array);
}

print_r(array_insert(array(), array(a,b,c), 3));
// Array ( [3] => a [4] => b [5] => c )
print_r(array_insert(range(1,10), array(a,b,c), 3));
// Array ( [3] => a [4] => b [5] => c [0] => 1 [1] => 2 [2] => 3 [6] => 4 [7] => 5 [8] => 6 [9] => 7 [10] => 8 [11] => 9 [12] => 10 )
print_r(array_insert(range(1,2), array(a,b,c), 3));
// Array ( [3] => a [4] => b [5] => c [0] => 1 [1] => 2 )
print_r(array_insert(array(10=>10,3=>3), array(a,b,c), 3));
// Array ([3] => a [4] => b [5] => c [6] => 10 [7] => 3 )
0