在PHP中任意位置插入数组新项

622

我该如何在数组中的任何位置插入一个新项目,比如在数组中间?


5
可能是如何在特定位置插入数组元素?的重复问题。 - Kashyap Kotak
23个回答

1182

你可能会觉得这种方法更加直观。它只需要一个函数调用来使用array_splice

$original = array( 'a', 'b', 'c', 'd', 'e' );
$inserted = array( 'x' ); // not necessarily an array, see manual quote
 
array_splice( $original, 3, 0, $inserted ); // splice in at position 3
// $original is now a b c x d e

如果替换只有一个元素,则不需要将其放入array()中,除非该元素本身就是一个数组、对象或NULL。

返回值:请注意,函数不会返回所需的替换结果。 $original 是按引用传递并在原地编辑的。请参见表达式 array &$array 中的 &参数列表中。


52
这样一种基本功能实际上有点隐蔽,因为在文档中描述的主要目的是其他的(替换数组中的内容),虽然在参数部分中有指出。但是如果你只是浏览函数描述以找出用于在数组中插入内容的函数,你可能永远都不会找到它。 - Mahn
40
这句话的意思是:仅仅这样做不能保留$inserted数组中的键。 - mauris
6
在PHP手册中,例如第一条:http://php.net/manual/en/function.array-splice.php - marcovtwout
3
@JacerOmri 完全正确,两种语句都是有效的。您可以传递任何类型的值,但对于数组、对象或 null,它们可能不能表现出相同的行为。对于标量,类型转换(array)$scalar等同于 array($scalar),但对于数组、对象或 null,它将被忽略 (array),转换为数组 (object),或成为空数组 (null) - 请参见 http://php.net/manual/en/language.types.array.php#language.types.array.casting - Lukas
3
@SunilPachlangia, adelval 和其他人:使用多维数组时,您需要将替换操作包装在一个数组中。这一点已经有记录了。我将这个提示提到这里,希望能让人们停止犯这个错误。 - Félix Adriyel Gagnon-Grenier
显示剩余2条评论

65

一种可以在整数和字符串位置都能插入的函数:

/**
 * @param array      $array
 * @param int|string $position
 * @param mixed      $insert
 */
function array_insert(&$array, $position, $insert)
{
    if (is_int($position)) {
        array_splice($array, $position, 0, $insert);
    } else {
        $pos   = array_search($position, array_keys($array));
        $array = array_merge(
            array_slice($array, 0, $pos),
            $insert,
            array_slice($array, $pos)
        );
    }
}

整数用法:

$arr = ["one", "two", "three"];
array_insert(
    $arr,
    1,
    "one-half"
);
// ->
array (
  0 => 'one',
  1 => 'one-half',
  2 => 'two',
  3 => 'three',
)

字符串用法:

$arr = [
    "name"  => [
        "type"      => "string",
        "maxlength" => "30",
    ],
    "email" => [
        "type"      => "email",
        "maxlength" => "150",
    ],
];

array_insert(
    $arr,
    "email",
    [
        "phone" => [
            "type"   => "string",
            "format" => "phone",
        ],
    ]
);
// ->
array (
  'name' =>
  array (
    'type' => 'string',
    'maxlength' => '30',
  ),
  'phone' =>
  array (
    'type' => 'string',
    'format' => 'phone',
  ),
  'email' =>
  array (
    'type' => 'email',
    'maxlength' => '150',
  ),
)

2
array_splice() 会丢失键,而 array_merge() 则不会。因此第一个函数的结果可能非常令人惊讶... 特别是如果您有两个具有相同键的元素,则只保留最后一个元素的值... - Alexis Wilke
我们还可以使用$array = array_slice($array, 0, $pos) + $insert + array_slice($array, $pos);来代替array_merge函数。这个函数将返回相同的输出结果。 - Syed Imran Ertaza

42
$a = array(1, 2, 3, 4);
$b = array_merge(array_slice($a, 0, 2), array(5), array_slice($a, 2));
// $b = array(1, 2, 5, 3, 4)

17
使用 + 符号代替 array_merge 可以保留原数组的键名。 - mauris
1
现在我可以在索引之前添加更多的元素。 - Abbas
数组合并只能合并数值型数组。所以你应该使用 + 而不是 array_merge。 - Saiful Islam
1
请忽略所有建议array_merge()不适用或数组联合运算符适用于数字键的评论。观看联合运算符的失败 - mickmackusa

12

如果您想保留初始数组的键,并添加一个具有键的数组,则使用下面的函数:

function insertArrayAtPosition( $array, $insert, $position ) {
    /*
    $array : The initial array i want to modify
    $insert : the new array i want to add, eg array('key' => 'value') or array('value')
    $position : the position where the new array will be inserted into. Please mind that arrays start at 0
    */
    return array_slice($array, 0, $position, TRUE) + $insert + array_slice($array, $position, NULL, TRUE);
}

调用示例:

$array = insertArrayAtPosition($array, array('key' => 'Value'), 3);

6
这个由Brad Erickson编写的函数对于关联数组在我的项目中非常有效:
/*
 * Inserts a new key/value after the key in the array.
 *
 * @param $key
 *   The key to insert after.
 * @param $array
 *   An array to insert in to.
 * @param $new_key
 *   The key to insert.
 * @param $new_value
 *   An value to insert.
 *
 * @return
 *   The new array if the key exists, FALSE otherwise.
 *
 * @see array_insert_before()
 */
function array_insert_after($key, array &$array, $new_key, $new_value) {
  if (array_key_exists($key, $array)) {
    $new = array();
    foreach ($array as $k => $value) {
      $new[$k] = $value;
      if ($k === $key) {
        $new[$new_key] = $new_value;
      }
    }
    return $new;
  }
  return FALSE;
}
该函数来源于这篇博客文章。还有一个方便的函数可以在特定键之前插入内容。

6

这是插入数组的方法:

function array_insert(&$array, $value, $index)
{
    return $array = array_merge(array_splice($array, max(0, $index - 1)), array($value), $array);
}

2
该函数没有将数组中的顺序保存。 - Daniel Petrovaliev
这个解决方案是误导性的/实现不好。这里有一个更正,它在合并之前使用array_splice()并正确排序元素组装。我理解为什么要使用max()!,但应该在答案中向研究人员解释,因为它涵盖了一个边缘情况。 - mickmackusa

6

据我所知,PHP没有一个原生的函数可以完全满足你的要求。

我写了两个方法,我认为它们很适合这个目的:

function insertBefore($input, $index, $element) {
    if (!array_key_exists($index, $input)) {
        throw new Exception("Index not found");
    }
    $tmpArray = array();
    $originalIndex = 0;
    foreach ($input as $key => $value) {
        if ($key === $index) {
            $tmpArray[] = $element;
            break;
        }
        $tmpArray[$key] = $value;
        $originalIndex++;
    }
    array_splice($input, 0, $originalIndex, $tmpArray);
    return $input;
}

function insertAfter($input, $index, $element) {
    if (!array_key_exists($index, $input)) {
        throw new Exception("Index not found");
    }
    $tmpArray = array();
    $originalIndex = 0;
    foreach ($input as $key => $value) {
        $tmpArray[$key] = $value;
        $originalIndex++;
        if ($key === $index) {
            $tmpArray[] = $element;
            break;
        }
    }
    array_splice($input, 0, $originalIndex, $tmpArray);
    return $input;
}

虽然更快且可能更节省内存,但这只适用于不需要保持数组键的情况。
如果您确实需要保持键,以下方法更合适;
function insertBefore($input, $index, $newKey, $element) {
    if (!array_key_exists($index, $input)) {
        throw new Exception("Index not found");
    }
    $tmpArray = array();
    foreach ($input as $key => $value) {
        if ($key === $index) {
            $tmpArray[$newKey] = $element;
        }
        $tmpArray[$key] = $value;
    }
    return $tmpArray;
}

function insertAfter($input, $index, $newKey, $element) {
    if (!array_key_exists($index, $input)) {
        throw new Exception("Index not found");
    }
    $tmpArray = array();
    foreach ($input as $key => $value) {
        $tmpArray[$key] = $value;
        if ($key === $index) {
            $tmpArray[$newKey] = $element;
        }
    }
    return $tmpArray;
}

4
没问题。但是在第二个例子中,你的函数insertBefore()里应该返回$tmpArray而不是$input - Christoph Fischer

5
基于@Halil的精彩回答,以下是一个简单函数,可以在保留整数键的情况下,在特定键后插入新元素:
private function arrayInsertAfterKey($array, $afterKey, $key, $value){
    $pos   = array_search($afterKey, array_keys($array));

    return array_merge(
        array_slice($array, 0, $pos, $preserve_keys = true),
        array($key=>$value),
        array_slice($array, $pos, $preserve_keys = true)
    );
} 

1
这个答案没有检查$pos是否为false - mickmackusa

5

如何通过使用 array_splice() 保留数组键

@jay.lee的答案是正确的,但不幸的是,它不会保留一个array的键,正如在评论中指出的:

$original = array( 
    'a' => 'A', 
    'b' => 'B', 
    'c' => 'C', 
    // insert here
    'd' => 'D', 
    'e' => 'E');

$inserted = array( 'x' => 'X' ); 

array_splice( $original, 3, 0, $inserted );
print_r($original);

/* Output
Array
(
    [a] => A
    [b] => B
    [c] => C
    [0] => X  <= the lost key 
    [d] => D
    [e] => E
) */

我发现保留数组键的最简单方法是使用array_splice()函数,并使用+/联合运算符将数组相加(也在另一个答案的评论中提到):
$original = array( 
    'a' => 'A', 
    'b' => 'B', 
    'c' => 'C', 
    // insert here
    'd' => 'D', 
    'e' => 'E');

$inserted = array( 'x' => 'X' ); 

// Insert before postion 'd'
$before = array_splice( $original, 0, 3 ); // $original contains the left over

// Merge together
$result = $before + $inserted + $original;
print_r($result);

/* Output
Array
(
    [a] => A
    [b] => B
    [c] => C
    [x] => X
    [d] => D
    [e] => E
) */

注意:仅在处理非数字键时使用数组合并运算符是安全的。


感谢更正 @mickmackusa


@mickmackusa,感谢您指出这一点。我已将其删除,因为它并不是解决方案的一部分。 - wittich

4
function insert(&$arr, $value, $index){       
    $lengh = count($arr);
    if($index<0||$index>$lengh)
        return;

    for($i=$lengh; $i>$index; $i--){
        $arr[$i] = $arr[$i-1];
    }

    $arr[$index] = $value;
}

这个答案缺少教育性的解释。 - mickmackusa

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