php array_splice() 用于关联数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1783089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 03:49:36  来源:igfitidea点击:

array_splice() for associative arrays

phparrays

提问by Pekka

Say I have an associative array:

假设我有一个关联数组:

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

and I want to introduce a new element into it:

我想在其中引入一个新元素:

"texture" => "bumpy" 

behind the 2nd item but preserving all the array keys:

在第二项后面,但保留所有数组键:

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

is there a function to do that? array_splice()won't cut it, it can work with numeric keys only.

有没有一个功能可以做到这一点?array_splice()不会剪,只能用数字键。

回答by soulmerge

I think you need to do that manually:

我认为您需要手动执行此操作:

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

回答by ragulka

Based on soulmerge's answer I created this handy function:

根据soulmerge的回答,我创建了这个方便的功能:

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

回答by kmuenkel

I hate to beat an old issue to death, it seems like some people have come up with some similar answers to mine already. But I'd like to offer a version that I think is just a little more thorough. This function is designed to feel and behave -exactly- like the regular array_splice() one, including its return value and how it handles invalid or negative values. The only difference in that regard is that when defining a replacement array (or string or number) and not a length, you're allowed to use a null value for the length instead of having to pass count($array) as an argument. It will assume that much from a null. 0 is still 0 though.

我讨厌把一个老问题打死,似乎有些人已经想出了一些与我类似的答案。但我想提供一个我认为更彻底的版本。这个函数被设计成感觉和行为 - 完全 - 像常规的 array_splice() 一个,包括它的返回值以及它如何处理无效或负值。在这方面的唯一区别是,在定义替换数组(或字符串或数字)而不是长度时,您可以使用空值作为长度,而不必将 count($array) 作为参数传递。它会从一个空值假设那么多。0 仍然是 0。

The only difference in function is of course the $key value parameter, specifying what key to derive a position from to start making changes. The $offset has been left in as well, now used as a modifier for that initial position. Key conflicts will always favor the replacement array but also trigger a warning. And if the key parameter is null or blank, the function will look only to the offset parameter and behave like array_splice, except while maintaining key values. If the key is simply not found though, it will behave the same way array_splice does when given an offset that's beyond the array length; it appends it to the end.

功能上的唯一区别当然是 $key 值参数,指定从哪个键派生位置以开始进行更改。$offset 也被保留了下来,现在用作该初始位置的修饰符。键冲突总是有利于替换数组,但也会触发警告。如果 key 参数为 null 或空白,则该函数将只查看 offset 参数并表现得像 array_splice,除非维护 key 值。但是,如果根本找不到键,那么当给出超出数组长度的偏移量时,它的行为将与 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;
}

So then...

那么……

$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
)
*/

This could also be a simpler way to replace individual array keys while maintaining its position, without having to go through array_values and array_combine.

这也可能是一种更简单的方法来替换单个数组键,同时保持其位置,而无需通过 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: I just discovered, apparently array_merge() can't really tell the difference between associative array keys that just happen to be numbers, and regular sequential keys. Merging the arrays using the + operator instead of array_merge() avoids this problem.

编辑:我刚刚发现,显然 array_merge() 不能真正区分恰好是数字的关联数组键和常规顺序键之间的区别。使用 + 运算符而不是 array_merge() 合并数组可以避免这个问题。

回答by David

Here's another way:

这是另一种方式:

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);
}

回答by Ben Fransen

I'm not sure if there is a function for that, but you can iterate through your array, store the index and use array_push.

我不确定是否有一个函数,但是您可以遍历数组,存储索引并使用 array_push。

回答by dnagirl

Well, you can rebuild the array from scratch. But the easiest way to go through an associative array in a particular order is to keep a separate ordering array. Like so:

好吧,您可以从头开始重建阵列。但是以特定顺序遍历关联数组的最简单方法是保留一个单独的排序数组。像这样:

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

回答by Colin Knapp

There is a super simple way to do this that I came up with tonight.It will search for a key, splice it like normal and return the removed element like the normal function.

今晚我想出了一个超级简单的方法来做到这一点。它会搜索一个键,像正常一样拼接它,然后像正常函数一样返回删除的元素。

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

回答by JohnK

This works like array_splice, but preserves the keys of the inserted array:

这类似于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;
    }

You use this as you would array_splice, but just add a kat the end. (ragulka's answer is good, but this makes it easier to adapt existing code.) So, for example

您可以像使用它一样使用它array_splice,但只需k在最后添加一个。(ragulka 的回答很好,但这可以更容易地适应现有代码。)所以,例如

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

Instead of

代替

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

use

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

Then $awill contain the result you're looking for.

然后$a将包含您正在寻找的结果。

回答by Luxian

Based on solution provided by ragulka and soulmerge, I created a slightly different functionthat let's you specify the 'key' instead of offset.

基于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)
  ;
}
?>

回答by codearachnid

Similar to @Luxian's answer I arrived at a similar method and set it up as array_splice_key. https://gist.github.com/4499117

与@Luxian 的回答类似,我采用了类似的方法并将其设置为 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;
}