如何在特定位置向数组中插入元素?

222

假设我们有两个数组:

$array_1 = array(
  '0' => 'zero',
  '1' => 'one',
  '2' => 'two',
  '3' => 'three',
);

$array_2 = array(
  'zero'  => '0',
  'one'   => '1',
  'two'   => '2',
  'three' => '3',
);

现在,我想要在每个数组的第三个元素之后插入 array('sample_key' => 'sample_value') 。我该如何做?


可能是 在 PHP 中的任何位置插入数组中的新项 的重复。 - Kashyap Kotak
不是重复的问题,这个问题更集中于关联数组,@KashyapKotak - anthony_718
25个回答

261

array_slice()函数可以用来提取数组的部分内容,而联合数组操作符(+则可将这些部分重新组合。

$res = array_slice($array, 0, 3, true) +
    array("my_key" => "my_value") +
    array_slice($array, 3, count($array)-3, true);

这个例子:

$array = array(
  'zero'  => '0',
  'one'   => '1',
  'two'   => '2',
  'three' => '3',
);
$res = array_slice($array, 0, 3, true) +
    array("my_key" => "my_value") +
    array_slice($array, 3, count($array) - 1, true) ;
print_r($res);
数组
(
    [zero] => 0
    [one] => 1
    [two] => 2
    [my_key] => my_value
    [three] => 3
)

10
按照M42的建议,您应该使用array_splice()。这只需要一行代码就可以解决问题。 - nickh
35
不应使用+操作符!请改用array_merge函数!因为如果数组索引是整数(普通数组,不是哈希表),+操作符将无法按预期工作!!! - Tomas
5
无论是否符合你的期望,这取决于你的期望。array_merge对数字键的行为不适用于这个问题。 - Artefacto
16
不必使用 count($array)-3,您可以直接指定为null以达到相同的效果。另外,正如TMS建议的那样,使用array_merge不需要使用唯一索引。例如:将“new-value”添加到现有数组中:$b = array_merge(array_slice($a, 0, 1, true), array('new-value'), array_slice($a, 1, null, true)); - Radley Sustaire
2
关于+array_merge之间似乎存在一些混淆。如果你想要将东西插入到一个数字数组中,你不应该使用+,因为它可能无法满足你的期望。但是你也不应该使用array_merge;对于数字数组,这个问题可以通过array_splice函数来解决。对于关联数组或混合数组,你可能不希望数字键被重新索引,所以使用+是完全适当的。 - meustrus
显示剩余5条评论

126

对于您的第一个数组,使用array_splice()函数:

$array_1 = array(
  '0' => 'zero',
  '1' => 'one',
  '2' => 'two',
  '3' => 'three',
);

array_splice($array_1, 3, 0, 'more');
print_r($array_1);

输出:

Array(
    [0] => zero
    [1] => one
    [2] => two
    [3] => more
    [4] => three
)

对于第二个,没有顺序,所以你只需要执行:

$array_2['more'] = '2.5';
print_r($array_2);

并且可以按照您想要的方式对键进行排序。


39
第二个数组确实有顺序......因为它们也是双向链表,所以所有的数组都有顺序。 - Artefacto
@M42 当您遍历foreach循环时,数组肯定是有顺序的。这可能重要也可能不重要,这取决于您的最终目标是什么。(我遇到了这个线程,因为在我的情况下,顺序很重要)。非常令人沮丧的是,关联数组没有array_splice()这样的东西。 - cartbeforehorse
7
如提到的,"没有顺序"这一说法是不正确的。此外,在第一个例子中,array_splice会破坏键/值的关联(但也许原帖作者就是这么想做的)。 - Brad Koch
2
@Artefacto 在 PHP 中,“数组”实际上是“有序哈希表”。PHP 数组的行为类似于数组,但它们从来不是真正的数组;也不是链表或数组列表。 - Frederik Krautwald
1
5个小时后,我终于读懂了一个答案,谢谢!还有一件额外的事情需要注意,如果有人正在推动一个关联数组,他们也可以在array_splice的第四个参数中指定“array”...就像这样:array_splice($array_1, 3, 0, ARRAY($array_name_to_insert)); - Robert Sinclair
1
@FrederikKrautwald 自 PHP 7 开始,这个说法已经不再正确。PHP 7 使用两个数组来实现其哈希表+有序列表。以下是来自 PHP 核心开发人员(Nikic)的一篇文章:https://nikic.github.io/2014/12/22/PHPs-new-hashtable-implementation.html - CubicleSoft

24

代码:

function insertValueAtPosition($arr, $insertedArray, $position) {
    $i = 0;
    $new_array=[];
    foreach ($arr as $key => $value) {
        if ($i == $position) {
            foreach ($insertedArray as $ikey => $ivalue) {
                $new_array[$ikey] = $ivalue;
            }
        }
        $new_array[$key] = $value;
        $i++;
    }
    return $new_array;
}

例子:

$array        = ["A"=8, "K"=>3];
$insert_array = ["D"= 9];

insertValueAtPosition($array, $insert_array, $position=2);
// result ====> ["A"=>8,  "D"=>9,  "K"=>3];

可能看起来并不完美,但它能正常工作。


13
你基本上是在尝试拼接,不要重新发明轮子。 - Paul Dragoonis
11
不,他没有重新发明轮子。array_splice()函数不允许设置键和值,只能将特定位置的值作为键和值。 - Kirzilla
1
是的,但正如之前所提到的,array_splice不支持关联数组。我很乐意看到更优雅的方法。 - clausvdb
你的函数非常好,但是当插入位置大于数组长度时它无法正常工作(尝试执行这个 array_insert($array_2, array("wow" => "wow"), 4))。不过这很容易修复。你的回答很棒,解决了我的问题! - Kirzilla

16

这里有一个简单的函数,可以直接使用。只需要插入即可。

这是按索引插入,而不是按值插入。

您可以选择传递数组,或者使用已经声明的数组。

新的、更短的版本:

   function insert($array, $index, $val)
   {
       $size = count($array); //because I am going to use this more than one time
       if (!is_int($index) || $index < 0 || $index > $size)
       {
           return -1;
       }
       else
       {
           $temp   = array_slice($array, 0, $index);
           $temp[] = $val;
           return array_merge($temp, array_slice($array, $index, $size));
       }
   }

旧的、较长的版本:

  function insert($array, $index, $val) { //function decleration
    $temp = array(); // this temp array will hold the value 
    $size = count($array); //because I am going to use this more than one time
    // Validation -- validate if index value is proper (you can omit this part)       
        if (!is_int($index) || $index < 0 || $index > $size) {
            echo "Error: Wrong index at Insert. Index: " . $index . " Current Size: " . $size;
            echo "<br/>";
            return false;
        }    
    //here is the actual insertion code
    //slice part of the array from 0 to insertion index
    $temp = array_slice($array, 0, $index);//e.g index=5, then slice will result elements [0-4]
    //add the value at the end of the temp array// at the insertion index e.g 5
    array_push($temp, $val);
    //reconnect the remaining part of the array to the current temp
    $temp = array_merge($temp, array_slice($array, $index, $size)); 
    $array = $temp;//swap// no need for this if you pass the array cuz you can simply return $temp, but, if u r using a class array for example, this is useful. 
  
     return $array; // you can return $temp instead if you don't use class array
}

使用示例:

//1
$result = insert(array(1,2,3,4,5),0, 0);
echo "<pre>";
echo "<br/>";
print_r($result);
echo "</pre>";
//2
$result = insert(array(1,2,3,4,5),2, "a");
echo "<pre>";
print_r($result);
echo "</pre>";
//3
$result = insert(array(1,2,3,4,5) ,4, "b");
echo "<pre>";
print_r($result);
echo "</pre>";
//4
$result = insert(array(1,2,3,4,5),5, 6);
echo "<pre>";
echo "<br/>";
print_r($result);
echo "</pre>";

预期结果:

//1
Array
(
    [0] => 0
    [1] => 1
    [2] => 2
    [3] => 3
    [4] => 4
    [5] => 5
)
//2
Array
(
    [0] => 1
    [1] => 2
    [2] => a
    [3] => 3
    [4] => 4
    [5] => 5
)
//3
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => b
    [5] => 5
)

//4
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 6
)

12
$list = array(
'Tunisia' => 'Tunis',
'Germany' => 'Berlin',
'Italy' => 'Rom',
'Egypt' => 'Cairo'
);
$afterIndex = 2;
$newVal= array('Palestine' => 'Jerusalem');

$newList = array_merge(array_slice($list,0,$afterIndex+1), $newVal,array_slice($list,$afterIndex+1));

只是提一下:现在可以使用数组之间的 + 号,而不是 array_merge。 - roelleor
@roelleor 但要小心:「如果输入的数组具有相同的字符串键,则该键的后一个值将覆盖前一个值。但是,如果数组包含数字键,则后一个值不会覆盖原始值,而是会被附加。」- array_merge - long
谢谢!这是唯一一个对我有效的考虑到关联数组的答案。 - Pablo S G Pacheco

6

如果您想在某个键后插入元素或数组,最简单的解决方案是:

function array_splice_after_key($array, $key, $array_to_insert)
{
    $key_pos = array_search($key, array_keys($array));
    if($key_pos !== false){
        $key_pos++;
        $second_array = array_splice($array, $key_pos);
        $array = array_merge($array, $array_to_insert, $second_array);
    }
    return $array;
}

那么,如果您有以下情况:

$array = [
    'one' => 1,
    'three' => 3
];
$array_to_insert = ['two' => 2];

并执行:

$result_array = array_splice_after_key($array, 'one', $array_to_insert);

你将获得:

Array ( 
    ['one'] => 1 
    ['two'] => 2 
    ['three'] => 3 
)

6

该函数支持:

  • 数字和关联键
  • 在找到的键之前或之后插入
  • 如果未找到键,则追加到数组末尾

function insert_into_array( $array, $search_key, $insert_key, $insert_value, $insert_after_founded_key = true, $append_if_not_found = false ) {

        $new_array = array();

        foreach( $array as $key => $value ){

            // INSERT BEFORE THE CURRENT KEY? 
            // ONLY IF CURRENT KEY IS THE KEY WE ARE SEARCHING FOR, AND WE WANT TO INSERT BEFORE THAT FOUNDED KEY
            if( $key === $search_key && ! $insert_after_founded_key )
                $new_array[ $insert_key ] = $insert_value;

            // COPY THE CURRENT KEY/VALUE FROM OLD ARRAY TO A NEW ARRAY
            $new_array[ $key ] = $value;

            // INSERT AFTER THE CURRENT KEY? 
            // ONLY IF CURRENT KEY IS THE KEY WE ARE SEARCHING FOR, AND WE WANT TO INSERT AFTER THAT FOUNDED KEY
            if( $key === $search_key && $insert_after_founded_key )
                $new_array[ $insert_key ] = $insert_value;

        }

        // APPEND IF KEY ISNT FOUNDED
        if( $append_if_not_found && count( $array ) == count( $new_array ) )
            $new_array[ $insert_key ] = $insert_value;

        return $new_array;

    }

用法:

    $array1 = array(
        0 => 'zero',
        1 => 'one',
        2 => 'two',
        3 => 'three',
        4 => 'four'
    );

    $array2 = array(
        'zero'  => '# 0',
        'one'   => '# 1',
        'two'   => '# 2',
        'three' => '# 3',
        'four'  => '# 4'
    );

    $array3 = array(
        0 => 'zero',
        1 => 'one',
       64 => '64',
        3 => 'three',
        4 => 'four'
    );


    // INSERT AFTER WITH NUMERIC KEYS
    print_r( insert_into_array( $array1, 3, 'three+', 'three+ value') );

    // INSERT AFTER WITH ASSOC KEYS
    print_r( insert_into_array( $array2, 'three', 'three+', 'three+ value') );

    // INSERT BEFORE
    print_r( insert_into_array( $array3, 64, 'before-64', 'before-64 value', false) );

    // APPEND IF SEARCH KEY ISNT FOUNDED
    print_r( insert_into_array( $array3, 'undefined assoc key', 'new key', 'new value', true, true) );

结果:

Array
(
    [0] => zero
    [1] => one
    [2] => two
    [3] => three
    [three+] => three+ value
    [4] => four
)
Array
(
    [zero] => # 0
    [one] => # 1
    [two] => # 2
    [three] => # 3
    [three+] => three+ value
    [four] => # 4
)
Array
(
    [0] => zero
    [1] => one
    [before-64] => before-64 value
    [64] => 64
    [3] => three
    [4] => four
)
Array
(
    [0] => zero
    [1] => one
    [64] => 64
    [3] => three
    [4] => four
    [new key] => new value
)

5
如果您不确定要将其插入到第3个位置,但知道要在哪个键后面插入它,那么在看到这个问题后,我编写了这个小函数。
/**
     * Inserts any number of scalars or arrays at the point
     * in the haystack immediately after the search key ($needle) was found,
     * or at the end if the needle is not found or not supplied.
     * Modifies $haystack in place.
     * @param array &$haystack the associative array to search. This will be modified by the function
     * @param string $needle the key to search for
     * @param mixed $stuff one or more arrays or scalars to be inserted into $haystack
     * @return int the index at which $needle was found
     */                         
    function array_insert_after(&$haystack, $needle = '', $stuff){
        if (! is_array($haystack) ) return $haystack;

        $new_array = array();
        for ($i = 2; $i < func_num_args(); ++$i){
            $arg = func_get_arg($i);
            if (is_array($arg)) $new_array = array_merge($new_array, $arg);
            else $new_array[] = $arg;
        }

        $i = 0;
        foreach($haystack as $key => $value){
            ++$i;
            if ($key == $needle) break;
        }

        $haystack = array_merge(array_slice($haystack, 0, $i, true), $new_array, array_slice($haystack, $i, null, true));

        return $i;
    }

这里有一个Codepad Fiddle可以看到它的运作方式:http://codepad.org/5WlKFKfz 注意:array_splice() 比 array_merge(array_slice()) 更高效,但是你插入的数组的键将会丢失。唉。

非常有用!做得很好。 - undefined

5
使用array_splice而不是array_slice可以减少一个函数调用。
$toto =  array(
  'zero'  => '0',
  'one'   => '1',
  'two'   => '2',
  'three' => '3'
);
$ret = array_splice($toto, 3 );
$toto = $toto +  array("my_key" => "my_value") + $ret;
print_r($toto);

5

我最近编写了一个类似于你试图实现的功能的函数,这是一种类似于clasvdb答案的方法。

function magic_insert($index,$value,$input_array ) {
  if (isset($input_array[$index])) {
    $output_array = array($index=>$value);
    foreach($input_array as $k=>$v) {
      if ($k<$index) {
        $output_array[$k] = $v;
      } else {
        if (isset($output_array[$k]) ) {
          $output_array[$k+1] = $v;
        } else {
          $output_array[$k] = $v;
        }
      } 
    }

  } else {
    $output_array = $input_array;
    $output_array[$index] = $value;
  }
  ksort($output_array);
  return $output_array;
}

基本上,它会在特定位置插入,但通过将所有项向下移动来避免覆盖。

尝试使用magic_insert(3, array("wow" => "wow"), $array_2)函数,其中$array_2取自问题文本。 - Kirzilla
我不会期望这个能够运行,因为$array_2是关联数组,而位置的概念在这种情况下通常不相关。 - Peter O'Callaghan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接