Подтвердить что ты не робот

Array_splice() для ассоциативных массивов

Скажем, у меня есть ассоциативный массив:

array(
  "color" => "red",
  "taste" => "sweet",
  "season" => "summer"
);

и я хочу ввести в него новый элемент:

"texture" => "bumpy" 

за вторым элементом, но сохраняя все ключи массива:

array(
  "color" => "red",
  "taste" => "sweet",
  "texture" => "bumpy", 
  "season" => "summer"
);

есть ли функция для этого? array_splice() не будет вырезать его, он может работать только с цифровыми клавишами.

4b9b3361

Ответ 1

Думаю, вам нужно сделать это вручную:

# Insert at offset 2
$offset = 2;
$newArray = array_slice($oldArray, 0, $offset, true) +
            array('texture' => 'bumpy') +
            array_slice($oldArray, $offset, NULL, true);

Ответ 2

На основе ответа soulmerge я создал эту удобную функцию:

function array_insert($array,$values,$offset) {
    return array_slice($array, 0, $offset, true) + $values + array_slice($array, $offset, NULL, true);  
}

Ответ 3

Мне не нравится бить старую проблему до смерти, похоже, что некоторые люди уже придумали какие-то похожие ответы на мои вопросы. Но я бы хотел предложить версию, которая, я думаю, немного более тщательна. Эта функция предназначена для того, чтобы чувствовать и вести себя-точно, как обычный массив array_splice(), включая его возвращаемое значение и то, как он обрабатывает недопустимые или отрицательные значения. Единственное отличие в этом отношении заключается в том, что при определении заменяющего массива (или строки или числа), а не длины, вам разрешено использовать значение null для длины вместо того, чтобы передавать счет ($ array) в качестве аргумента. Он будет считать, что многое из нуля. 0 все равно 0.

Единственное различие в функции - это, конечно, параметр $key value, определяющий, какой ключ для получения позиции, чтобы начать вносить изменения. Смещение $также оставлено, теперь оно используется в качестве модификатора для этой начальной позиции. Ключевые конфликты всегда будут способствовать замене массива, но также вызовут предупреждение. И если ключевой параметр пуст или пуст, функция будет выглядеть только для параметра offset и вести себя как array_splice, за исключением сохранения значений ключа. Если ключ просто не найден, он будет вести себя так же, как это делает array_splice, если задано смещение, выходящее за пределы длины массива; он добавляет его до конца.

/**
 * Remove or replace elements of an associative array by key value.
 * @param Object array $input The input associative array
 * @param string $key The key whose position in the array determines the start of the removed portion.
 * @param int $offset Adjust the start position derived from the key by this value.
 * If the sum is positive, it starts from the beginning of the input array.  If negative, it starts from the far end.
 * @param int $length If length is omitted or null, remove everything from key position to the end of the array.
 * If positive, that many elements will be removed.
 * If negative, then the end of the removed portion will be that many elements from the end of the array.
 * @param mixed $replacement Elements from this array will be inserted at the position of the designated key.
 * @return array  Returns the array of the extracted elements.
 */
function array_splice_assoc(&$input, $key, $offset = 0, $length = null, $replacement = null)
{
    if (!is_array($input)) {
        $trace = debug_backtrace();
        extract($trace[0]);
        trigger_error(
            __FUNCTION__."(): expects parameter 1 to be an array, ".gettype($input)." given from $file on line $line",
            E_USER_WARNING
        );
        return false;
    }
    $offset = (int)$offset;
    $replacement = (array)$replacement;
    $inputLength = count($input);
    if (!is_null($key) && $key !== "") {
        $index = array_search($key, $keys = array_keys($input));
        if ($index === false) {
            $offset = $inputLength;
        }
        $offset += $index;
    }
    $index = array_search($key, $keys = array_keys($input));
    if ($index === false) {
        $offset = $inputLength;
    }
    $offset += $index;
    if ($offset < 0) {
        $offset += $inputLength;
        if ($offset < 0) {
            $offset = 0;
        }
    }
    if (is_null($length)) {
        $length = $inputLength;
    } elseif ($length < 0) {
        $length += $inputLength - $offset;
    }
    $extracted = array_slice($input, $offset, $length, true);
    $start = array_slice($input, 0, $offset, true);
    $end = array_slice($input, $offset + $length, $inputLength, true);
    $remaining = $start + $end;
    if (count($conflict = array_keys(array_intersect_key($remaining, $replacement)))) {
        $trace = debug_backtrace();
        extract($trace[0]);
        trigger_error(
            __FUNCTION__."(): key conflict from $file on line $line",
            E_USER_WARNING
        );
        foreach ($conflict as $key) {
            if (isset($start[$key])) {
                unset($start[$key]);
            } else {
                unset($end[$key]);
            }
        }
    }
    $input = (!empty($replacement)) ? $start + $replacement + $end : $remaining;
    return $extracted;
}

Итак, тогда...

$array1 = array(
    "fruit1" => "apple",
    "vegetable1" => "carrot",
    "vegetable2" => "potato",
    "fruit2" => "orange",
    "fruit3" => "banana",
    "fruit4" => "pear"
);

$array2 = array(
    "snack" => "chips",
    "vegetable3" => "green bean",
    "vegetable1" => "corn"
);

$vegetables = array_splice_assoc($array1, "fruit1", 1, -3);
print_r($array1);
print_r($vegetables);

array_splice_assoc($array2, "vegetable3", -1, 1, $vegetables);
print_r($array2);

/* Output is:
Array
(
    [fruit1] => apple
    [fruit2] => orange
    [fruit3] => banana
    [fruit4] => pear
)
Array
(
    [vegetable1] => carrot
    [vegetable2] => potato
)
PHP Warning:  array_splice_assoc(): key conflict from /var/www/php/array_splice_assoc.php on line 97 in /var/www/php/array_splice_assoc.php on line 65
Array
(
    [vegetable1] => carrot
    [vegetable2] => potato
    [vegetable3] => green bean
)
*/

Это также может быть более простой способ заменить отдельные ключи массива при сохранении его положения, без необходимости проходить через array_values ​​и array_combine.

$array3 = array(
    "vegetable1" => "carrot",
    "vegetable2" => "potato",
    "vegetable3" => "tomato",
    "vegetable4" => "green bean",
    "vegetable5" => "corn"
);

array_splice_assoc($array3, null, 2, 1, array("fruit1" => $array3['vegetable3']));
print_r($array3);

/* OUTPUT:
Array
(
    [vegetable1] => carrot
    [vegetable2] => potato
    [fruit1] => tomato
    [vegetable4] => green bean
    [vegetable5] => corn
)
*/

EDIT: Я только что обнаружил, что, по-видимому, array_merge() не может отличить между ассоциативными ключами массива, которые просто являются числами, и регулярными последовательными ключами. Слияние массивов с помощью оператора + вместо array_merge() позволяет избежать этой проблемы.

Ответ 4

Я не уверен, есть ли функция для этого, но вы можете выполнять итерацию через свой массив, хранить индекс и использовать array_push.

Ответ 5

Ну, вы можете перестроить массив с нуля. Но самый простой способ пройти через ассоциативный массив в определенном порядке - это сохранить отдельный массив упорядочения. Например:

$order=array('color','taste','texture','season');
foreach($order as $key) {
  echo $unordered[$key];
}

Ответ 6

Здесь другой способ:

function array_splice_assoc(&$input, $offset, $length = 0, $replacement = array()) {
  $keys = array_keys($input);
  $values = array_values($input);
  array_splice($keys, $offset, $length, array_keys($replacement));
  array_splice($values, $offset, $length, array_values($replacement));
  $input = array_combine($keys, $values);
}

Ответ 7

На основе решения, предоставленного ragulka и soulmerge, я создал slightly different function, которые позволяют вам указывать "ключ" вместо смещения.

<?php
/**
 * Insert values in a associative array at a given position
 *
 * @param array $array
 *   The array in which you want to insert
 * @param array $values
 *   The key => values you want to insert
 * @param string $pivot
 *   The key position to use as insert position.
 * @param string $position
 *   Where to insert the values relative to given $position.
 *   Allowed values: 'after' - default or 'before'
 *
 * @return array
 *   The resulted array with $values inserted a given position
 */
function array_insert_at_position($array, $values, $pivot, $position = 'after'){
  $offset = 0;
  foreach($array as $key => $value){
    ++$offset;
    if ($key == $pivot){
      break;
    }
  }

  if ($position == 'before'){
    --$offset;
  }

  return
    array_slice($array, 0, $offset, TRUE)
    + $values
    + array_slice($array, $offset, NULL, TRUE)
  ;
}
?>

Ответ 8

Существует очень простой способ сделать это, что я придумал tonight.It будет искать ключ, сплайсировать его, как обычно, и вернуть удаленный элемент, как нормальная функция.

function assoc_splice($source_array, $key_name, $length, $replacement){
    return array_splice($source_array, array_search($key_name, array_keys($source_array)), $length, $replacement);
}

Ответ 9

Это работает как array_splice, но сохраняет ключи вставленного массива:

    function array_splicek(&$array, $offset, $length, $replacement) {
        if (!is_array($replacement)) {
            $replacement = array($replacement);
        }
        $out = array_slice($array, $offset, $length);
        $array = array_slice($array, 0, $offset, true) + $replacement
            + array_slice($array, $offset + $length, NULL, true);
        return $out;
    }

Вы используете это, как и array_splice, но просто добавьте k в конец. (ответ ragulka хорош, но это облегчает адаптацию существующего кода.) Итак, например

$a = array("color" => "red", "taste" => "sweet", "season" => "summer");
$b = array("texture" => "bumpy");

Вместо

array_splice($a, 2, 0, $b);

использование

array_splicek($a, 2, 0, $b);

Затем $a будет содержать результат, который вы ищете.

Ответ 10

Мое решение имитирует array_splice точно, второй параметр теперь String $key, вместо Int $offset,

function array_splice_assoc ( &$input ,$key, $length = 0 , $replacement = null ){

    $keys = array_keys( $input );
    $offset = array_search( $key, $keys );

    if($replacement){
        $values = array_values($input);
        $extracted_elements = array_combine(array_splice($keys, $offset, $length, array_keys($replacement)),array_splice($values, $offset, $length, array_values($replacement)));
        $input = array_combine($keys, $values);
    } else {
        $extracted_elements = array_slice($input, $offset, $length);
    }
    return $extracted_elements;
}

Итак, чтобы получить требуемый результат, вы будете делать

$array = array(
  "color" => "red",
  "taste" => "sweet",
  "season" => "summer"
);
$replacement = array("texture" => "bumpy");


array_splice_assoc ($array ,"season", 0, $replacement);

Выход

Array
(
    [color] => red
    [taste] => sweet
    [texture] => bumpy
    [season] => summer
)

Ответ 11

Важное примечание: оно не будет работать, если ключи не находятся в массиве.

Мое решение (я люблю использовать собственные функции php-массива);

$startIndex = array_search($firstKey, array_keys($arr);
$endIndex = array_search($secondKey, array_keys($arr));
array_splice($arr, $startIndex, $endIndex - $startIndex);

Это довольно просто, и вы можете легко превратить его в функцию.

Ответ 12

function insrt_to_offest($targetArr, $toBeEmbed, $indAfter) {
    $ind = array_search($indAfter, array_keys($targetArr));
    $offset = $ind + 1;

    # Insert at offset 2    
    $newArray = array_slice($targetArr, 0, $offset, true) +
    $toBeEmbed +
    array_slice($targetArr, $offset, NULL, true); 

    return $newArray;
}


$features = array(
            "color" => "red",
            "taste" => "sweet",
            "season" => "summer"
          );

print_r($features);

$toBeEmbed = array("texture" => "bumpy");

$newArray = insrt_to_offest($features, $toBeEmbed, 'taste');

print_r($newArray);

Ответ 13

Подобно @Luxian answer, я пришел к аналогичному методу и настроил его как array_splice_key. https://gist.github.com/4499117

/**
 * Insert another array into an associative array after the supplied key
 *
 * @param string $key
 *   The key of the array you want to pivot around
 * @param array $source_array
 *   The 'original' source array
 * @param array $insert_array
 *   The 'new' associative array to merge in by the key
 *
 * @return array $modified_array
 *   The resulting merged arrays
 */
function array_splice_after_key( $key, $source_array, $insert_array ) { 
    return array_splice_key( $key, $source_array, $insert_array );
}

/**
 * Insert another array into an associative array before the supplied key
 *
 * @param string $key
 *   The key of the array you want to pivot around
 * @param array $source_array
 *   The 'original' source array
 * @param array $insert_array
 *   The 'new' associative array to merge in by the key
 *
 * @return array $modified_array
 *   The resulting merged arrays
 */
function array_splice_before_key( $key, $source_array, $insert_array ) { 
    return array_splice_key( $key, $source_array, $insert_array, -1 );
} 

/**
 * Insert another array into an associative array around a given key
 *
 * @param string $key
 *   The key of the array you want to pivot around
 * @param array $source_array
 *   The 'original' source array
 * @param array $insert_array
 *   The 'new' associative array to merge in by the key
 * @param int $direction
 *   Where to insert the new array relative to given $position by $key
 *   Allowed values: positive or negative numbers - default is 1 (insert after $key)
 *
 * @return array $modified_array
 *   The resulting merged arrays
 */
function array_splice_key( $key, $source_array, $insert_array, $direction = 1 ){
    $position = array_search( $key, array_keys( $source_array ) ) + $direction;

    // setup the return with the source array
    $modified_array = $source_array;

    if( count($source_array) < $position && $position != 0 ) {
        // push one or more elements onto the end of array
        array_push( $modified_array, $insert_array );
    } else if ( $position < 0 ){
        // prepend one or more elements to the beginning of an array
        array_unshift( $modified_array, $insert_array );
    } else {
        $modified_array = array_slice($source_array, 0, $position, true) +
            $insert_array +
            array_slice($source_array, $position, NULL, true);
    }
    return $modified_array;
}